Haskell的inline-C能否将typedef返回给函数指针?

时间:2019-01-22 20:25:12

标签: c haskell ffi inline-c

我正在使用的C代码库

typedef void(* wl_notify_func_t) (struct wl_listener *listener, void *data) 

//...

struct wl_listener {
  struct wl_list link;
  wl_notify_func_t notify; //<-- I'd like to return this
};

并已使用Haskell代码

type NotifyFuncT = FunPtr (Ptr C'WlListener -> Ptr () -> IO ())

initializeMyCtx = C.context $ C.baseCtx <> C.funCtx <> mempty {
  C.ctxTypesTable = Data.Map.fromList [
     (C.Struct "wl_listener", [t|C'WlListener|])
  -- ...
  ,  (C.TypeName "wl_notify_func_t", [t|NotifyFuncT|])
  ]
}

someHaskellFunction :: Ptr C'WlListener -> IO NotifyFuncT
someHaskellFunction ptrToWlListener = do
  funPtr <- [C.block| wl_notify_func_t {return $(struct wl_listener * ptrToWlListener)->notify;}|]
  return funPtr

不幸的是,我从inline-C代码块中得到了一个错误,该错误基本上是这样的:

unexpected identifier  wl_notify_func_t

那么使用inline-C甚至可以做什么?

2 个答案:

答案 0 :(得分:6)

您使用的上下文不正确。

C.context :: Context -> Q [Dec]

它被称为“模板Haskell”顶层接头。您所要做的就是定义

intializeMyCtx :: Q [Dec]

这是一个Q动作,如果被执行,初始化您的上下文,但是不是。因此,请解决此问题:

type NotifyFuncT = FunPtr (Ptr C'WlListener -> Ptr () -> IO ())

C.context $ C.baseCtx <> C.funCtx <> mempty {
  C.ctxTypesTable = Data.Map.fromList [
     (C.Struct "wl_listener", [t|C'WlListener|])
  -- ...
  ,  (C.TypeName "wl_notify_func_t", [t|NotifyFuncT|])
  ]
}

第二,someHaskellFunction有点复杂。如果您具有更复杂的功能,则可以考虑使用C.block,但是现在只需一个C.exp就可以完成所有工作。

someHaskellFunction :: Ptr C'WlListener -> IO NotifyFuncT
someHaskellFunction ptr = [C.exp| wl_notify_func_t { $(struct wl_listener *ptr)->notify } |]

答案 1 :(得分:0)

我的问题中的代码有效。我只是忘了包含C上下文。