Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble importing a C function into Haskell

Tags:

c

haskell

ffi

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.

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)
like image 908
MCH Avatar asked Dec 19 '25 11:12

MCH


1 Answers

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

like image 54
Reid Barton Avatar answered Dec 21 '25 01:12

Reid Barton



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!