3

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?

Community
  • 1
  • 1
Flash
  • 107
  • 8
  • "Is this sure to work cross-platform?" Do you mean "is this code portable to different platforms?" or "if I send one of these structures from one system (e.g., network host, compiler, etc.) to another, will it still work?" – Joshua Taylor May 10 '14 at 13:46
  • @Joshua-Taylor I edited to clarify. I do not intend to send structures across different platforms, I only want to be sure that this code is portable, and does not just work coincidentally for me. – Flash May 10 '14 at 14:18
  • I think, that this depends on the ABI of the system. I wouldn't bet, that something like this could reliably be done across multiple OSes on the same processor, let alone across different processor architectures. – Dirk May 10 '14 at 16:11
  • 1
    @Flash Note that sizeof(struct) is very possible can be not equal to sizeof(int) + sizeof(int) + sizeof(bool). Compiler can add padding bytes to structure, so void func(mystruct) is not the same as void func(int, int, bool) from the binary compatibility standpoint. – cybevnm May 12 '14 at 15:38

1 Answers1

0

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 =].
andrew
  • 2,819
  • 24
  • 33