当我发现Addr#
类型时,我最近一直在环顾各种Haskell怪癖,比如未装箱的类型等等。
GHC.Prim
包描述如下:
假定任意机器地址指向垃圾收集堆之外。
这对我来说意义不大。
此外,我一直在寻找使用类型的函数:
readIntOffAddr# :: Addr# -> Int# -> State# s -> (#State# s, Int##)
这是什么类型的?我该怎么办?为什么有必要?
答案 0 :(得分:8)
作为迈克尔回答的补充:
Addr#
是Ptr a
下的未装箱类型,与Int#
是Int
下的未装箱类型的方式相同。其内容可能被解释为机器地址,但就编译器和GC而言,它只是另一种整数类型(无论系统中的大小指针是什么)。因为它是一个任意的机器地址而不是GC管理的指针,所以它应该不会指向Haskell堆,因为Haskell堆对象的地址从Haskell级别看是不稳定的(GC可能在任何一点发生)你的程序,然后你Addr#
所指向的任何对象都存在于其他地方,或者根本没有任何对象。
通常Ptr a
/ Addr#
将包含从malloc
/ mmap
/等返回的指针,或指向C全局变量的指针,或者通常任何指针指针可能在C程序中明显指向的东西。通常在与C函数接口时使用readIntOffAddr#
,该函数返回或修改传递的HsInt *
的内容。 (好吧,你不会直接使用它,你会使用Int
的{{1}} peekElemOff
方法,我认为这是按照Storable
实现的,或者你会使用更高级别的函数,如readIntOffAddr#
)。
答案 1 :(得分:7)
等效的* C代码为:
long readIntOffAddr(long *ptr, long offset) {
return ptr[offset];
}
Addr#
就像void *
一样。该函数具有IO
- 类似签名,因为它不是纯粹的#34;。多次调用函数可能会返回不同的值(显然)。
* 更新(2018年):我刚刚了解到将C&#39 {1}}类型与Haskell int
类型等同是错误的。因此,我在上面的代码段中将Int#
更改为int
。这也(可能)不是100%正确,但至少对于我所见过的所有GHC实现都是如此。在GHC版本6-8(没有检查其他版本)中,long
在32位平台上为32位宽,在64位平台上为64位宽。这与我所知道的32位和64位平台上所有C / C ++实现的Int#
的GCC行为相匹配,所以我认为将long
与Int#
等同起来是一个良好的第一近似。在过去3年中没有人注意到这种轻微的不准确性(或者足以编辑/评论),所以请不要为此向我投降。我怀疑是否有任何Haskell / Platform / C组合long
!= HsInt
其中Haskell实现具有long
函数..请证明我错了。