Monday, June 15, 2009

FFI: C function taking pointer to array

Say you want to call the following C function from Haskell: The parameter tarray is a pointer to an array of floats. From C, you'd use it along the following lines:
    float times[2];
    printf("user time=%f, system time=%f\n", times[0], times[1]);
But in the Haskell world, even though such destructive updates are anathema, we can still talk back and forth.

First, we enable the Foreign Function Interface language pragma:

> {-# LANGUAGE ForeignFunctionInterface #-}
Then some front matter:
> module Main where
> import Foreign (Ptr)
> import Foreign.Marshal.Array (allocaArray,peekArray)
> import Control.Monad (mapM_)
We let Haskell know about the C function we want to call with an import declaration:
> foreign import ccall etime_ :: Ptr Float -> IO Float
To prepare for the call to the C function, allocaArray creates a new buffer and passes a handle to it (ta in the example below) to an action that calls etime_, pulls the data with peekArray, and returns these values along with the value returned from etime_ in a tuple:
> etime :: IO (Float, Float, Float)
> etime = do
>   allocaArray 2 $ \ta -> do
>     t <- etime_ ta
>     [user,sys] <- peekArray 2 ta
>     return (t,user,sys)
Use the etime action as in the following example:
> main :: IO ()
> main = do
>   (t,user,sys) <- etime
>   putStrLn $ "user time:    " ++ show user
>   putStrLn $ "system time:  " ++ show sys
>   putStrLn $ "process time: " ++ show t

No comments: