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)

      

+3


source to share


1 answer


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, like malloc

    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 for void *

    so that you can pass its address as the first argument malloc_

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

+1


source







All Articles