我有一个关于Haskell C FFI的问题,具体是关于如何访问由C库导出的静态数据结构。
我要包装的C库有像下面的
我要包装的C库有像下面的
FOO_GEORGE
这样的静态数据结构,以以下方式导出:static struct foo_struct foo_table[] = { /* list of foo structs */ }
typedef struct foo_struct *foo_t;
foo_t FOO_GEORGE = &foo_table[0];
foo_t FOO_HARRY = &foo_table[1];
foo_t FOO_SUSAN = &foo_table[2];
/* ... */
我在我的Haskell库中需要的值是foo_struct
的地址(&foo_table[n]
),也就是FOO_GEORGE
的内容,通常情况下会将其放入不透明的新类型包装器中(构造函数不会从库中导出,只导出类型):
newtype Foo = Foo { getFoo :: (Ptr Foo) }
这是我现在正在做的事情:
foreign import ccall "&FOO_GEORGE" fooGeorgeHandle :: Ptr (Ptr Foo)
FooGeorge = Foo . unsafeDupablePerformIO . peek $ fooGeorgeHandle
我认为这是一个适当使用 unsafePerformIO
的例子,因为 C API 和实现表明这种使用 peek
是纯净的且没有副作用。此外,我相信我不需要采取文档中列出的符号开头的任何预防措施 (从 {-# NOINLINE foo #-}
开始)。
我的总问题是:我做得对吗?上面的分析是否正确?有更好或更可取的方法吗?如果 foreign import
子句允许我进行指针引用,那就太好了,但似乎不行;我有遗漏吗?可以说这将是一个糟糕的特性,因为如果指针无效会导致段错误,但这同样也适用于我必须使用的 peek
,所以本质上并无区别。
谢谢!
CApiFFI
(或者其他文档中提到的内容),但是看起来很有前途。我会试一下并回报结果。谢谢! - Richard E. SilvermanCApiFFI
,所以我不确定它是否有效。 - John L