Search code examples
haskellc2hs

Returning a bare struct from C to Haskell in c2hs


I'm trying to bind to a C function that returns a struct (by value). I know I can wrap it manually using the FFI, but can't figure out how to coax c2hs into generating the correct code. It seems to think my function is returning a pointer.

Here's a simple example:

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'#}

The error:

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 ())

Solution

  • It is not possible currently. You can make a wrapper that returns the result by pointer:

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

    Note that you have to allocate space for the structure, e.g. using alloca.

    There is a proposal to support passing and returning C structures by value in FFI. But it is unlikely to be implemented in near future because it didn't get enough attention from the community. The proposal needs more careful design, e.g. it is not clear how it will work with other language features.