“C”wiringPi库中有一个类型为
的函数extern void (*pinMode) (int pin, int mode) ;
我尝试使用带有FunPtr的FFI从haskell调用它。所以我做到了,
foreign import ccall unsafe "wiringPi.h &pinMode" c_pinMode
:: FunPtr (CInt -> CInt -> IO ())
foreign import ccall "dynamic" dc_pinMode
:: FunPtr (CInt -> CInt -> IO ()) -> (CInt -> CInt -> IO ())
但由于某种原因,即使它编译,也似乎没有调用'pinMode'指向的函数。
所以我尝试使用普通的Foreign.Ptr,认为我可以窥探Ptr以获得对'pinMode'指向的底层'C'函数的引用。所以我试过了,
foreign import ccall "wiringPi.h &pinMode" c_pinMode
:: Ptr (Ptr (CInt -> CInt -> IO ()))
然后,在调用'pinMode'的haskell函数的实现中,我使用peek两次来获取对底层函数的引用。但是我一直在编译错误,编译器告诉我类型(CInt -> CInt -> IO ())
的函数不是'Storable'类型类的实例。
所以我检查了可存储的类型类,使(CInt -> CInt -> IO ())
成为可存储的类型类的实例。所需的最小实现是窥视,戳和其他一些函数..我意识到,它真的不应该如此难以调用由指针引用的函数..
我觉得我错过了一些基本的东西。有人可以指出我正确的方向吗?
谢谢和问候
答案 0 :(得分:2)
假设我们在foo.c中定义了一个C函数指针。
void foo(int x, int y)
{
printf("foo: sum = %d\n", x+y);
}
typedef void (*FooPtr) (int, int);
FooPtr fooptr = foo;
为了调用fooptr
指向的函数,我们不仅需要声明静态地址导入,还需要动态导入。动态存根可以帮助我们将FunPtr
值转换为相应的Haskell函数。
type Foo = CInt -> CInt -> IO ()
foreign import ccall "foo.c &fooptr" fooptr :: Ptr (FunPtr Foo)
foreign import ccall "dynamic" mkFooFun :: FunPtr Foo -> Foo
main = do
funcptr <- peek fooptr
mkFooFun funcptr 1 2
fooptr
是导入的地址,指向外部函数。它的类型既不是Ptr (Ptr a)
也不是FunPtr a
。
如果我们导入foo
的地址,其类型将为FunPtr Foo
。为了使用它,我们仍然需要mkFooFun
的帮助。
foreign import ccall "foo.c &foo" fooptr2 :: FunPtr Foo
main = mkFooFun fooptr2 1 2
在此示例中,由于我们可以访问foo
,因此调用foo
的最简单方法是
foreign import ccall "foo.c foo" foo :: Foo
main = foo 1 2