1

“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 ())不是“可存储”类型类的实例。

所以我检查了可存储类型类,以创建可存储类型类(CInt -> CInt -> IO ())的实例。所需的最低实现是 peek、poke 和其他一些函数。我意识到,调用一个函数真的不应该那么难由指针引用..

我觉得我错过了一些基本的东西。有人可以指出我正确的方向吗?

谢谢并恭祝安康

4

1 回答 1

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

如果我们 importfoo的地址,它的类型将是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
于 2013-03-05T08:30:35.820 回答