什么是Addr#类型,我如何使用它



当我发现Addr#类型时,我最近一直在寻找各种Haskell怪癖,如未装箱类型和诸如此类的东西。

GHC.Prim包是这样描述的:

假定指向垃圾收集堆外部的任意机器地址。

这对我来说意义不大。

此外,我不断发现像这样使用类型的函数:

readIntOffAddr# :: Addr# -> Int# -> State# s -> (#State# s, Int##)

这是什么类型?我能用它做什么?为什么有必要?

作为Michael回答的补充:

Addr#Ptr a下面的未装箱类型,同理Int#Int下面的未装箱类型。它的内容可能被解释为机器地址,尽管就编译器和GC而言,它只是另一种整型(无论系统上指针的大小如何)。因为它是一个任意的机器地址,而不是GC管理的指针,它应该不会指向Haskell堆,因为从Haskell的层面来看,Haskell堆对象的地址是不稳定的(GC可能发生在你的程序中的任何一点,然后你的Addr#指向的对象现在在其他地方,或者根本不在任何地方)。

通常Ptr a/Addr#将包含从malloc/mmap/等返回的指针。或者是指向C全局变量的指针,或者是C程序中指针可能指向的任何类型的东西。当与返回或修改传递的HsInt *的内容的C函数接口时,通常使用readIntOffAddr#。(嗯,你不会直接使用它,你会使用IntpeekElemOff Storable方法,我认为这是根据readIntOffAddr#实现的,或者你会使用peekArray这样的更高级的函数)。

等效的* C代码为:

long readIntOffAddr(long *ptr, long offset) {
    return ptr[offset];
}

Addr#void *一样。该函数具有类似IO的签名,因为它不是"纯净"的。对函数的多次调用可能返回不同的值(很明显)。

* Update (2018):我刚刚了解到将C的int类型等同于Haskells的Int#类型是错误的。因此,我在上面的代码片段中将int更改为long。这也(也许)不是100%正确,但至少对于我所见过的所有GHC实现都是如此。在GHC版本6-8中(没有检查其他版本),Int#在32位平台上是32位宽,在64位平台上是64位宽。这与我所知道的32位和64位平台上所有C/c++实现的long的GCC行为相匹配,因此我认为将Int#long等同是一个很好的近似。在过去的3年里,没有人注意到这个小错误(或者足够关心编辑/评论)。我怀疑是否有任何Haskell/Platform/C组合,其中HsInt != long,其中Haskell实现具有readIntOffAddr#功能。

最新更新