I have functions that do the following sort of thing.
CStructType* foo;
int result = someFunctionThatAllocsFooAsOutput(&foo);
The first thing that comes to mind after reading around about this stuff is:
-- Standard binding done elsewhere
data CStructType = CStructType {
-- Stuff here
} deriving (Eq, Show)
foreign import ccall "some_c_header.h someFunctionThatAllocsFooAsOutput" someFunction :: CStructType Ptr -> IO CInt
-- Call function binding from somewhere
main :: IO ()
main = do
result <- alloca $ \cstruct -> someFunction cstruct
doOtherThings cstruct result
However, I don't know of this is valid, or if it's valid, if it's the best practice.
I'm reasonably new to Haskell, so I apologize if there's any major stupidity in this post.
I think your code is not quite correct. First consider what happens in the C idiom: you allocate a pointer to CStructType on the stack, then pass a pointer to that pointer as the argument to someFunctionThatAllocsFooAsOutput
. That function is responsible for allocating a new CStructType
(probably via malloc
), and the resulting new pointer is stored into the pointer you've created on the stack.
To replicate this in Haskell, the important point is that rather than marshaling back and forth, you need to retain a pointer to the memory allocated by someFunctionThatAllocsFooAsOutput
and pass that in to C functions until you're ready to free it. So you will probably want to do something like this (I haven't tried to compile this, but I think it's close):
newtype CStructPtr = CStructPtr (ForeignPtr CStructType)
foreign import ccall "some_c_header.h someFunctionThatAllocsFooAsOutput" someFunction :: Ptr (Ptr CStructType) -> IO CInt
-- we need a hook into the function to free a `CStructType`
foreign import ccall "some_c_header.h &freeFoo" freeFoo :: FunPtr (Ptr CStructType -> IO ())
allocFoo :: IO (CStructPtr, CInt)
allocFoo = alloca $ \ptrptr -> do
result <- someFunction ptrptr
cstructptr <- peek ptrptr
fPtr <- newForeignPtr freeFoo cstructptr
return (CStructPtr fPtr, result)
-- a useful unwrapper
withCStruct :: CStructPtr -> (Ptr CStructType -> IO a) -> IO a
withCStruct (CStructPtr fPtr) action = withForeignPtr fPtr action
doOtherThings :: CStructPtr -> CInt -> IO ()
doOtherThings ptr result = withCStruct ptr $ \cptr -> otherCFunction cptr result
main = do
(cstruct,result) <- allocFoo
doOtherThings cstruct result
A couple points to note:
ForeignPtr
s, you can just keep a raw Ptr CStructType
and pass it into function directly. This gets rather inconvenient though because you'll need to manually free it, which usually involves a top-level bracket
.someFunctionThatAllocsFooAsOutput
involves global state, pointers to other malloc'd memory, or other trickiness. If you know more about CStructType
, it might not be necessary to retain the exact memory returned by someFunctionThatAllocsFooAsOutput
and you could more freely marshal the data to Haskell. But there's not enough information here for me to assume that.As others have pointed out, the FFI
chapter of Real World Haskell is quite relevant. I don't think it has an example of using output params though, which is an unfortunate omission.