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.)