【问题标题】:How to call a C function that uses a callback in Haskell?如何在 Haskell 中调用使用回调的 C 函数?
【发布时间】:2016-03-15 09:25:17
【问题描述】:

我正在尝试使用c2hsHaskell 调用以下C 函数。

void rd_kafka_conf_set_rebalance_cb (
    rd_kafka_conf_t *conf,
    void (*rebalance_cb) (rd_kafka_t *rk,
                          rd_kafka_resp_err_t err,
                          rd_kafka_topic_partition_list_t *partitions,
                          void *opaque));

我不熟悉c2hs,并且在声明绑定时遇到了麻烦。

这是我尝试过的:

--callback type
type RebalanceCbFun = 
    Ptr RdKafkaT -> CInt -> Ptr RdKafkaTopicPartitionListT -> Ptr Word8 -> IO ()

foreign import ccall safe "wrapper" 
    mkRebalanceCallback :: RebalanceCbFun -> IO (FunPtr RebalanceCbFun)

foreign import ccall unsafe "rd_kafka.h &rd_kafka_conf_set_rebalance_cb"
    rdKafkaConfSetRebalanceCb :: Ptr RdKafkaConfT -> FunPtr RebalanceCbFun -> IO ()

但是在编译这段代码时出现以下错误:

Unacceptable type in foreign declaration:
  ‘Ptr RdKafkaConfT
   -> FunPtr
        (Ptr RdKafkaT
         -> Int32 -> Ptr RdKafkaTopicPartitionListT -> Ptr Word8 -> IO ())
   -> IO ()’ cannot be marshalled in a foreign call
  A foreign-imported address (via &foo) must have type (Ptr a) or (FunPtr a)
When checking declaration:
  foreign import ccall unsafe "static rd_kafka.h &rd_kafka_conf_set_rebalance_cb" rdKafkaConfSetRebalanceCb
    :: Ptr RdKafkaConfT -> FunPtr RebalanceCbFun -> IO ()

我不明白这里缺少PtrFunPtr 的哪一部分。 我还尝试将整个 rdKafkaConfSetRebalanceCb 包装到 FunPtr 中,例如:

foreign import ccall unsafe "rd_kafka.h &rd_kafka_conf_set_rebalance_cb"
    rdKafkaConfSetRebalanceCb :: FunPtr (Ptr RdKafkaConfT -> FunPtr RebalanceCbFun -> IO ())

不确定它是否有意义,尽管它可以编译...... 但是后来我不知道如何使用这个功能,这是我尝试过的(这是我最后想要的签名):

kafkaConfSetRebalanceCb :: RdKafkaConfTPtr -> RebalanceCbFun -> IO ()
kafkaConfSetRebalanceCb conf cb = do
    cb' <- mkRebalanceCallback cb
    withForeignPtr conf $ \c -> rdKafkaConfSetRebalanceCb c cb'
    return ()

现在它抱怨我没有要调用的函数,只有一个指向函数的指针(因为 FunPtr 包装)。

您能告诉我如何为上面的C 签名正确完成C 绑定吗?

【问题讨论】:

  • 未来访问者请注意:不能像这样将回调到 Haskell 代码中的 C 函数导入 unsafe

标签: haskell c2hs


【解决方案1】:

以下文件对我来说编译得很好(使用ghc -c Test.hs)。唯一真正的区别是我在国外导入中省略了&amp;

{-# LANGUAGE ForeignFunctionInterface #-}
module Test where
import Data.Word
import Foreign.C.Types
import Foreign.Ptr
import Foreign.ForeignPtr

newtype RdKafkaT = RdKafkaT (Ptr RdKafkaT)
newtype RdKafkaConfT = RdKafkaConfT (Ptr RdKafkaConfT)
newtype RdKafkaTopicPartitionListT = RdKafkaTopicPartitionListT (Ptr RdKafkaTopicPartitionListT)

type RebalanceCbFun = 
    Ptr RdKafkaT -> CInt -> Ptr RdKafkaTopicPartitionListT -> Ptr Word8 -> IO ()

foreign import ccall safe "wrapper" 
    mkRebalanceCallback :: RebalanceCbFun -> IO (FunPtr RebalanceCbFun)

foreign import ccall unsafe "rd_kafka.h rd_kafka_conf_set_rebalance_cb"
    rdKafkaConfSetRebalanceCb :: Ptr RdKafkaConfT -> FunPtr RebalanceCbFun -> IO ()

kafkaConfSetRebalanceCb :: ForeignPtr RdKafkaConfT -> RebalanceCbFun -> IO ()
kafkaConfSetRebalanceCb conf cb = do
    cb' <- mkRebalanceCallback cb
    withForeignPtr conf $ \c -> rdKafkaConfSetRebalanceCb c cb'

【讨论】:

  • 哇,真的!我什至没有注意到它在那里!非常感谢!
猜你喜欢
  • 2015-06-25
  • 2020-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-23
  • 2016-02-02
  • 2022-10-01
  • 2012-06-10
相关资源
最近更新 更多