如何在没有c2hs或其他工具的情况下为此结构创建可存储的实例?

时间:2015-05-30 15:58:37

标签: c haskell ffi

这个结构:

typedef struct Atom_ {
    float x;
    float y;
    float z;
    int col;
} Atom;

对应于此类型:

data Atom = Atom { pos :: V3 Float, col :: Int }

如何为Atom创建一个可存储的实例,以便我可以将Haskell上的Atom发送到需要Atom的C函数?

1 个答案:

答案 0 :(得分:3)

我目前无法保证这将完全按照显示的方式工作(我没有在此计算机上设置环境),但它应该是朝着正确的方向迈出的良好的第一步:

import Foreign.Storable
import Foreign.Ptr

instance Storable Atom where
    -- Don't make this static, let the compiler choose depending
    -- on the platform
    sizeOf _ = 3 * sizeOf (0 :: Float) + sizeOf (0 :: Int)
    -- You may need to fiddle with this, and with your corresponding C
    -- code if you have the ability to, alignment can be tricky, but
    -- in this case you can pretty safely assume it'll be the alignment
    -- for `Float`
    alignment _ = alignment (0 :: Float)
    -- These are pretty straightforward, and obviously order matters here
    -- a great deal.  I clearly haven't made this the most optimized it
    -- could be, I'm going for clarity of code instead
    peek ptr = do
        let floatSize = sizeOf (0 :: Float)
        x   <- peek $ ptr `plusPtr` (0 * floatSize)
        y   <- peek $ ptr `plusPtr` (1 * floatSize)
        z   <- peek $ ptr `plusPtr` (2 * floatSize)
        col <- peek $ ptr `plusPtr` (3 * floatSize)
        return $ Atom (V3 x y z) col
    poke ptr (Atom (V3 x y z) col) = do
        let floatSize = sizeOf (0 :: Float)
        poke (ptr `plusPtr` (0 * floatSize)) x
        poke (ptr `plusPtr` (1 * floatSize)) y
        poke (ptr `plusPtr` (2 * floatSize)) z
        poke (ptr `plusPtr` (3 * floatSize)) col

这应该有效!它可能高度依赖于您的C编译器和您的平台,但是,您需要进行一些广泛的测试以确保它已正确布局。