在c2hs中将一个简单的结构从C返回到Haskell

时间:2015-05-14 10:52:14

标签: haskell c2hs

我正在尝试绑定到一个返回struct(按值)的C函数。我知道我可以使用FFI手动包装它,但无法弄清楚如何哄骗c2hs生成正确的代码。它似乎认为我的函数正在返回一个指针。

这是一个简单的例子:

module Point where

#c
struct point {
  int x;
  int y;
};

struct point get_zero(void);
#endc

data Point = Point { x :: Int, y :: Int }

instance Storable Point where
    sizeOf _ = {#sizeof point#}
    alignment _ = {#alignof point#}
    peek p = point <$> liftA fromIntegral ({#get point.x #} p)
                   <*> liftA fromIntegral ({#get point.y #} p)
    poke p s = do {#set point.x #} p (fromIntegral $ x s)
                  {#set point.y #} p (fromIntegral $ y s)

{#pointer *point as PointPtr -> Point#}

-- Causes error:
{#fun get_zero as ^ { } -> `Point'#}

错误:

c2hs: Errors during expansion of binding hooks:

Point.chs:25: (column 28) [ERROR]  >>> Missing "out" marshaller!
  There is no default marshaller for this combination of Haskell and C type:
  Haskell type: Point
  C type      : (Ptr ())

1 个答案:

答案 0 :(得分:4)

目前不可能。您可以创建一个通过指针返回结果的包装器:

void get_zero_wrapper(struct point* p) {
  *p = get_zero();
}

请注意,您必须为结构分配空间,例如使用alloca

有一个proposal支持在FFI中按值传递和返回C结构。但它不太可能在不久的将来实施,因为它没有得到社区的足够重视。该提案需要更仔细的设计,例如目前尚不清楚它如何与其他语言功能一起使用。