I've done this for some code, in both directions. (https://github.com/SimulaVR/godot-haskell/blob/simula/src/Godot/Gdnative/Internal/Gdnative.chs#L378)

`Foo makeFoo(size_t x)` is internally equivalent (ABI-dependent, but at least on x64 Linux and WIndows) to `Foo* makeFoo(Foo* result, size_t x)`. Alloc the data in Haskell and use that definition.

On 2020-06-16 16:44, ☂Josh Chia (謝任中) wrote:
Suppose I have the following C code:

typedef struct Foo {
    char* p1;  /* Some data on the heap. */
    size_t s1; /* Size of data. */
    char* p2;  /* More data on the heap. */
    size_t s2;
} Foo;

/* Allocates and writes two pieces of data on the heap and returns them in a Foo. */
Foo makeFoo(size_t x);

Based on my limited understanding of Haskell FFI according to the Haskell 2010 Language Report (https://www.haskell.org/onlinereport/haskell2010/haskellch8.html), it is not possible to have a ccall for makeFoo() because Foo is not a marshallable foreign result type. Is my understanding correct?

However, I believe I can have a ccall if I change makeFoo() to either of the following:
Foo* makeFoo(size_t x);
void makeFoo(Foo* out, size_t x);

The first involves the C code allocating a Foo and returning a pointer to it (so now there's one more pointer for the C code to deallocate later in another function). The second involves the C code writing a Foo value to a piece of memory allocated in Haskell (possibly using Foreign.Marshall.Alloc.alloca). Both signatures work because Foo* is marshallable but are clumsier to use than the original signature. Is there just no way to return a struct by value on the stack? Is there a cleaner way than the above two?

Josh

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.