将数据从C传递到Haskell并返回

时间:2016-07-20 15:47:32

标签: haskell ffi

我目前正在编写Haskell绑定到GEGL库,它最初是用C编写的。这是我第一次使用FFI,所以我可能错过了一些东西。

我的问题是,我在这样的代码中得到了段错误:

-- | Simple iteration over a rectangle section of a buffer.
iterateOver   
  :: GeglBuffer               -- ^ Target buffer
  -> GeglRectangle            -- ^ Rectangle to iterate over
  -> BablFormat               -- ^ Pixel format
  -> GeglAccessMode           -- ^ Access mode to pixel data
  -> GeglAbyssPolicy          -- ^ Abbyss policy for pixel data
  -> (Pixel -> Pixel) -- Function to apply to each pixel
  -> IO ()
iterateOver buf rect form am ap func = do
  traceIO "start"
  (FFI.GeglBufferIterator iterPtr) <- gegl_buffer_iterator_new buf rect form am ap
  traceIO "new iterator"
  untilM_ (do
    floats <-  map (\(CFloat f) -> f) <$> FFI.c_gegl_peek_data iterPtr -- Code breaks here
    traceIO "peeked data"
    let ops =  buildPixelList rect floats
        nps =  map func ops
        nfl =  map CFloat $ buildFloatList nps
    FFI.c_gegl_poke_data iterPtr nfl
    traceIO "poked data"                                                        
    ) ( not <$> gegl_buffer_iterator_next (FFI.GeglBufferIterator iterPtr))
  traceIO "finished"

c_gegl_peek_data函数已使用inline-c编写,如下所示:

-- | Get the list of pixel data out of a 'GeglBufferIterator'.
c_gegl_peek_data
  :: GeglBufferIteratorDummy -- ^ Iterator to take data from
  -> IO [CFloat]
c_gegl_peek_data ptr = do
  fptr <- [C.block| float * {
    GeglBufferIterator * cptr =  $(void * ptr);
    float * a = (float *) cptr->data[0];
    return a;
    }|]
  (CInt length) <- [C.block| int {
    GeglBufferIterator * cptr = $(void * ptr);
    int a = cptr->length;
    return a;
    }|]
  peekArray (fromIntegral length :: Int) fptr

你们有人可以指出我的错误在哪里吗?

提前致谢。

修改

这是一个同样问题的小型自包含示例。它只需要inline-c包。

{-#LANGUAGE QuasiQuotes #-}
{-#LANGUAGE OverloadedStrings #-}
{-#LANGUAGE TemplateHaskell #-}
{-#LANGUAGE ForeignFunctionInterface #-}

module Main where

import qualified Language.C.Inline as C
import Foreign.Marshal.Array
import Debug.Trace

main :: IO ()
main = do
  traceIO "start"
  ptr <- [C.block| int * {
    int a[5] = {0,1,2,3,4};
    return a;
    }|]
  traceIO "got pointer"
  a <- peekArray 5 ptr
  traceIO "peeked pointer"
  putStrLn $ show a
  traceIO "finish"

此外,我为此示例添加了cabal文件:

name:                sandbox
version:             0.0.0.0
synopsis:            Small example
author:              nek0
maintainer:          nek0@nek0.eu
build-type:          Simple
cabal-version:       >=1.10

executable sandbox
  hs-source-dirs:      app
  main-is:             Main.hs
  c-sources:           app/Main.c
  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N
  build-depends:       base
                     , inline-c
  default-language:    Haskell2010

0 个答案:

没有答案