haskell之如何调用在 Haskell 中使用回调的 C 函数

Terrylee 阅读:89 2025-01-19 22:14:33 评论:0

我正在尝试使用 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,并且在声明绑定(bind)时遇到了麻烦。

这是我试过的:

--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 绑定(bind)吗?

请您参考如下方法:

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

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


标签:程序员
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号