Passing and returning structs to C functions on stack from Common Lisp with CFFI

StackOverflow https://stackoverflow.com/questions/23579340

  •  19-07-2023
  •  | 
  •  

Вопрос

This is sort-of a follow-up to the question Common lisp, CFFI, and instantiating c structs, so basically this question is about passing and returning c-structs to and from c-functions on the stack from Common Lisp with CFFI.

The answer to the question linked above (from 2010), was that this is not possible.

The current version of CFFI supports passing and returning structs on stack via libffi, as discussed in this question. However, libffi introduces another dependency, and libffi is not trivial to compile on all the systems I am targetting. I am therefore trying not to use libffi, as I only have very few such functions to call.

As discussed in the first question I linked to, it is possible to call c-functions that expect struct parameters on stack by deconstructing the struct. As an example, here is a struct and a function definition:

typedef struct
{
    int width;        
    int height;       
    bool isGreat; 
} mystruct;

int do_something(mystruct rect);

It is possible to call this function from Common Lisp using

(cffi:defcfun ("do_something" do-something)
    :int
  (width :int)
  (height :int)
  (is-great :boolean))

Now, I have two questions:

  1. Is this sure to work on all platforms? I would assume that in C, by definition structs in this situation are laid out exactly as the individual parameters would be, therefore this is guaranteed to work, but I am not sure.

  2. What about returning structs? Assuming a C function

    mystruct foo();
    

    Is there a possibility to call this somehow from Common Lisp, without using libffi, e.g. by telling CFFI how much memory the return structure will take, and then "parsing" it manually?

Это было полезно?

Решение

Original asker of the question you linked here.

I've tried the struct deconstructing technique and had varying degrees of success. It seems to work fine on Windows/Linux x86, but there were a few libraries I tried this with that did not want to cooperate (for instance, I was trying to wrap libuv in CFFI back when it took/returned structs for addresses). Lots of segfaults.

However for Chipmunk, the technique worked great on Windows/Linux with SBCL, CCL, ECL. However, the Chipmunk struct had two float members so it was very basic.

I'd say in general, the more complex your struct gets, the more trouble you're asking for. Also, not sure how this would port to non x86 platforms.

Your best bet is to write your bindings, try them on each platform you're targeting, and see what breaks. Another option, if you have time, is to write your own portable C wrapper that handles the heap/stack stuff for you. I don't like this though, because it's one more step between my library and its users, but so far (barring chipmunk and old versions of libuv) I've had the pleasure of working with C libs that expect pointers.

TL;DR:

  1. Maybe, try it.
  2. No. Expect segfaults. Sometimes emailing the maintainer of the C library and asking nicely will get you pointers instead of values though =].
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top