Problem importing C function into Haskell
I have a C program that calls a Haskell function. I want the Haskell function to be in charge of determining the size of the array (pointer), so I also want Haskell to malloc the pointer from C. I get an error when malloc_
called in Haskell. I'm not sure how to emulate the way malloc_
called in C malloc_((void *)&ints,sizeof(int),10);
in Haskell.
aux.c
void malloc_ (void **p, size_t size, int m) {
*p = malloc(size*m);
}
main.c
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]);
}
Arrays.hs
#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)
source to share
Ignoring other issues with your question and just addressing the challenge part malloc
: you have several options.
-
malloc
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 really want to use a different allocator), you will make things more convenient for yourself by simply returning the pointer value from your wrapper, likemalloc
doing it himself:void *malloc_ (size_t size, int m) { return malloc(size*m); }
then
foreign import ccall "malloc_" malloc_ :: CSize -> CInt -> IO (Ptr ())
and just name it. -
If you really want to use that style-argument
void malloc_ (void **p, size_t size, int m)
, then you need to allocate storage forvoid *
so that you can pass its address as the first argumentmalloc_
, just like you would in C.my_allocated_pointer <- with nullPtr $ \pp -> do malloc_ pp (fromIntegral $ sizeOf (undefined :: CInt)) (fromIntegral 10) peek pp
(Now this is starting to get a little silly, since with uses
malloc
internally ... but this approach will be used for you in general.)
source to share