假设您有一个提供 C 结构的 C API
typedef struct A {
int i;
float f;
} A;
以及填充它的函数:
void getA(A* a);
例如,这可能是从 C API 内部获取某些信息的 getter。
在 Haskell 中,C 结构将被镜像
data A = A {
i :: Int,
f :: Float
}
Storable
实例是
instance Storable A where
sizeOf _ = {#sizeof A #}
alignment _ = {#alignof A #}
peek p = ...
poke p x = ...
peek 和 poke 与c2hs 处理的{#get...#}
和pragma 一样正常。{#set #}
Haskell 函数getA :: IO A
应该类似于
{#fun unsafe getA as getA {alloca- `A' peek*} -> `()'#}
除了这不起作用,因为 c2hs 创建了这个绑定:
foreign import ccall unsafe "include/A.h getA"
_getA'_ :: Ptr () -> IO ()
它Ptr ()
作为第一个论点。这可以通过
{#fun unsafe getA as getA {allocaA- `A' peekA*} -> `()'#}
peekA :: Ptr () -> IO A
peekA = peek . castPtr
allocaA :: (Ptr () -> IO a) -> IO a
allocaA f = alloca $ \(p :: Ptr A) -> f (castPtr p)
这allocaA
很重要,因为它确保A
分配内存而不是仅使用()
if的内存alloca
。
虽然这可行,但它有点乏味,而且如果你忘记写allocaXYZ
而不是只写alloca
. (我刚刚看到花了很多时间来追踪一个这样的错误。)
我希望找到一个{#fun...#}
产生的咒语
foreign import ccall unsafe "include/A.h getA"
_getA'_ :: Ptr A -> IO ()
其他一切都会自然而然地遵循(注意Ptr A
代替Ptr ()
)。但据我所知,只有{allocXYZ- 'XYZ' peekXYZ*}
路线。
所以问题是:这可以用更好的方式完成c2hs
吗?