I have a C program that calls a Haskell function. I want the Haskell function to be responsible for determining the size of the array (pointer) so I also want Haskell to malloc the pointer from C. I get an error when malloc_ is called in Haskell. I am not sure how to emulate the way malloc_ is called in C malloc_((void *)&ints,sizeof(int),10); into Haskell.
void malloc_ (void **p, size_t size, int m) {
*p = malloc(size*m);
}
int *ints;
// want to call this function in Haskell, C doesn't know how large the array is
// malloc_((void *)&ints,sizeof(int),10);
int ints_size = setIntArray(ints);
for (int i = 0; i < ints_size; i++) {
printf("ints[%d]: %d\n", i, ints[i]);
}
#include "aux.h"
-- this might be wrong
foreign import ccall "malloc_" malloc_ :: Ptr (Ptr ()) -> CSize -> CInt -> IO ()
foreign export ccall "setIntArray" setIntArray :: Ptr CInt -> IO CInt
setIntArray :: Ptr CInt -> IO (CInt)
setIntArray is = do
let r = 10 :: Int
-- if I remove this and malloc in C then it is fine
malloc_ (castPtr is) (fromIntegral $ sizeOf is) (fromIntegral r)
x <- addArrayElement r 0
return $ fromIntegral x
where
addArrayElement :: Int -> Int -> IO Int
addArrayElement r pointerCounter =
case pointerCounter >= r of
True -> return r
False -> do
let x = 1234
poke (advancePtr is pointerCounter) (x :: CInt)
addArrayElement r (pointerCounter + 1)
Ignoring the other issues with your question, and just addressing the part about calling malloc: you have a few options.
malloc is already imported for you as malloc, or you can even use mallocArray in this case.
If you really want to import malloc yourself (maybe you actually want to use a different allocator), you'd make things more convenient for yourself by just returning the pointer value from your wrapper, like malloc itself does:
void *malloc_ (size_t size, int m) {
return malloc(size*m);
}
then foreign import ccall "malloc_" malloc_ :: CSize -> CInt -> IO (Ptr ()), and just call it.
If you really want to use this out-argument-style void malloc_ (void **p, size_t size, int m), then you have to allocate storage for a void *, so that you can pass its address as the first argument of malloc_, like you would do in C.
my_allocated_pointer <- with nullPtr $ \pp -> do
malloc_ pp (fromIntegral $ sizeOf (undefined :: CInt)) (fromIntegral 10)
peek pp
(This is now starting to get a bit silly, since with uses malloc internally... but it's the approach you would use in general.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With