使用hsc2hs

时间:2018-03-31 19:21:51

标签: c arrays haskell ffi

这是一个简单的h文件:

/* file marchingcubes.h */
typedef struct {
   double x,y,z;
} XYZ;

要在Haskell中定义类似的类型,我使用hsc2hs。我写这个文件CTypes.hsc

{-# LANGUAGE ForeignFunctionInterface #-}
module CTypes 
  where
import           Foreign
import           Foreign.C.Types

#include "marchingcubes.h"

data CXYZ = CXYZ {
    __x :: CDouble
  , __y :: CDouble
  , __z :: CDouble
}

instance Storable CXYZ where
    sizeOf    __ = #{size XYZ}
    alignment __ = #{alignment XYZ}
    peek ptr = do
      x' <- #{peek XYZ, x} ptr
      y' <- #{peek XYZ, y} ptr
      z' <- #{peek XYZ, z} ptr
      return CXYZ { __x = x'
                  , __y = y'
                  , __z = z' }
    poke ptr (CXYZ r1 r2 r3)
      = do
          #{poke XYZ, x} ptr r1
          #{poke XYZ, y} ptr r2
          #{poke XYZ, z} ptr r3

使用hs转换为hsc2hs之后和之后没问题。

现在我有另一个包含静态数组的结构:

typedef struct {
   XYZ p[3];
} TRIANGLE;

如何在hsc文件中定义Haskell中的类似类型?我可以拥有类似的东西:

data CTRIANGLE = CTRIANGLE {
  __p :: [CXYZ]
}

?我如何定义Storable实例?我发现了几个关于阵列和FFI的问题,但没有任何东西允许我解决这个问题。

更新

我已经完成了:

data CTRIANGLE = CTRIANGLE {
  __p :: [CXYZ]
}

instance Storable CTRIANGLE where
  sizeOf    __ = #{size TRIANGLE}
  alignment __ = #{alignment TRIANGLE}
  peek ptr = do
    p' <- peekArray 3 $ #{ptr TRIANGLE, p} ptr
    return CTRIANGLE { __p = p' }
  poke ptr (CXY r1) = do
    pokeArray (#{ptr TRIANGLE, p} ptr) r1

hsc2hs生成:

instance Storable CTRIANGLE where
  sizeOf    __ = (72)
{-# LINE 37 "CTypes.hsc" #-}
  alignment __ = 8
{-# LINE 38 "CTypes.hsc" #-}
  peek ptr = do
    p' <- peekArray 3 $ (\hsc_ptr -> hsc_ptr `plusPtr` 0) ptr
{-# LINE 40 "CTypes.hsc" #-}
    return CTRIANGLE { __p = p' }
  poke ptr (CXY r1) = do
    pokeArray ((\hsc_ptr -> hsc_ptr `plusPtr` 0) ptr) r1
{-# LINE 43 "CTypes.hsc" #-}

现在我必须测试一下是否有效。

1 个答案:

答案 0 :(得分:2)

我在更新中提供的代码有效:)

marchingcubes.hsc

data CTRIANGLE = CTRIANGLE {
  __p :: [CXYZ]
} deriving Show

instance Storable CTRIANGLE where
  sizeOf    __ = #{size TRIANGLE}
  alignment __ = #{alignment TRIANGLE}
  peek ptr = do
    p' <- peekArray 3 $ #{ptr TRIANGLE, p} ptr
    return CTRIANGLE { __p = p' }
  poke ptr (CTRIANGLE r1) = do
    pokeArray (#{ptr TRIANGLE, p} ptr) r1

foreign import ccall unsafe "testTriangle" c_testTriangle
  :: CDouble -> CDouble -> CDouble 
  -> IO (Ptr CTRIANGLE)

现在让我们检查一下。我做了一个文件marchingcubes.c

#include <stdlib.h>
#include "marchingcubes.h"

TRIANGLE* testTriangle(double a, double b, double c){
  XYZ xyz;
  xyz.x = a;
  xyz.y = b;
  xyz.z = c;
  TRIANGLE *tri = malloc(sizeof(TRIANGLE));
  tri[0].p[0] = xyz;
  tri[0].p[1] = xyz;
  tri[0].p[2] = xyz;
  return tri;
}

我做了一个模块:

module Lib
  where
import           CTypes
import           Foreign

someFunc :: IO CTRIANGLE
someFunc = do
    ptr <- c_testTriangle 1 2 3
    peek ptr

测试:

Prelude Lib> someFunc
CTRIANGLE {__p = [CXYZ {__x = 1.0, __y = 2.0, __z = 3.0},CXYZ {__x = 1.0, __y = 2.0, __z = 3.0},CXYZ {__x = 1.0, __y = 2.0, __z = 3.0}]}

这是期望的结果:)

不要忘记

  include-dirs:        C
  C-sources:           C/marchingcubes.c

cabal文件中。