在 Haskell2010 报告中,从第 8.4.2 节开始,列出了 FFI 进出口申报中支持的基本类型:
以下类型构成了一组基本的外来类型:
- 曲以及
Char
、Int
、Double
、Float
和Bool
,由哈斯克尔前奏Int8
、Int16
、Int32
、Int64
、Word8
、Word16
、Word32
、Word64
、Ptr a
、FunPtr a
和StablePtr a
,适用于任何类型的a
,如国外出口 (第24节)。实现FFI的Haskell系统需要能够通过 Haskell和外部上下文之间的这些类型作为函数 参数和结果。
在 GHC 手册中有关 FFI 扩展的部分,GHC 通过一些未装箱的类型添加到这些类型中:
以下未装箱类型可用作基本外来类型(请参阅 FFI 附录,第 3.2 节):
Int#
、Word#
、Char#
、Float#
、Double#
,Addr#
,StablePtr# a
,MutableByteArray#
,ForeignObj#
,ByteArray#
。
当我指定ccall
调用约定时,很明显在链接器级别上大多数这些类型会发生什么。例如,我很确定Int
/Int#
作为两个 32 位值在堆栈上传递。同样,Ptr a
/StablePtr a
/StablePtr# a
/Addr#
可能都作为堆栈上的指针传递。
ByteArray#
和MutableByteArray#
呢?
我所能想象的就是将它们作为指针传递,但这似乎有点疯狂,因为除非您将ByteArray#
/MutableByteArray#
固定,否则 GHC 运行时最终可能会从您下方移动数组。此外,您还将忽略数组上的大小信息。
感谢 @ThomasM.DuBuisson 挖掘出一个旧的电子邮件线程:
有一种方法可以通过未固定的
ByteArray#
(或MutableByteArray#
, 但前者在您的情况下似乎是正确的)拨打外国电话,使用UnliftedFFITypes
语言扩展。ByteArray#
保证 在通话期间不移动。代码应处理ByteArray#
参数,就好像它是指向字节的指针一样。您将需要 在 C 端进行任何地址偏移计算(即传递任何 偏移量作为 C 函数的额外参数)。
所以:这些是作为指针传递的,GHC 的运行时承诺不会将它们从你下面移动。