I have a question about the Haskell C FFI, specifically about accessing static data structures exported by a C library.
The C library I’m wrapping has static data structures like FOO_GEORGE
below, exported in the following fashion:
static struct foo_struct foo_table[] = { /* list of foo structs */ }
typedef struct foo_struct *foo_t;
foo_t FOO_GEORGE = &foo_table[0];
foo_t FOO_HARRY = &foo_table[1];
foo_t FOO_SUSAN = &foo_table[2];
/* ... */
The value I need in my Haskell library is the address of the foo_struct
(&foo_table[n]
), that is, the contents of FOO_GEORGE
, which is put in an opaque newtype wrapper in the usual way (the constructors are not exported from the library, only the type):
newtype Foo = Foo { getFoo :: (Ptr Foo) }
This is what I’m doing now:
foreign import ccall "&FOO_GEORGE" fooGeorgeHandle :: Ptr (Ptr Foo)
FooGeorge = Foo . unsafeDupablePerformIO . peek $ fooGeorgeHandle
I think this is an appropriate use of unsafePerformIO
, since the C API and implementation say that this use of peek
is pure and has no side effects. Also, I believe that I don’t need to take any of the precautions outlined in bullet points in the documentation (starting with {-# NOINLINE foo #-}
).
My overall question is: am I doing this right? Are the bits of analysis above correct? Is there a better or preferable way to do this? If the foreign import
clause allowed me to do the pointer defererence, that would be nice, but it doesn’t seem to; am I missing anything? One could argue that this would be a bad feature since it could segfault if the pointer is bad — but then, the same is true of the peek
I have to use instead, so it comes to the same thing.
Thanks!
unsafeDupablePerformIO
should be fine in this instance. Can you use the CApiFFI extension? haskell.org/ghc/docs/7.6.2/html/users_guide/ffi.html – John LCApiFFI
(or anything else documented there), but it looks promising. I'll try it out and report back. Thanks! – Richard E. SilvermanCApiFFI
so I wasn't sure it would work. – John L