【问题标题】:What is the Addr# type, and how can I use it?什么是 Addr# 类型,如何使用它?
【发布时间】:2015-12-08 09:20:49
【问题描述】:

当我发现 Addr# 类型时,我最近一直在寻找各种 Haskell 怪癖,比如未装箱类型等等。

GHC.Prim 包是这样描述的:

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

这对我来说意义不大。

此外,我一直在寻找像这样使用类型的函数:

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

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

【问题讨论】:

    标签: haskell primitive-types


    【解决方案1】:

    等效的* C 代码为:

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

    Addr# 就像void *。该函数具有类似IO 的签名,因为它不是“纯”的。多次调用该函数可能会返回不同的值(显然)。

    * 更新(2018 年): 我刚刚了解到将 C 的 int 类型等同于 Haskells Int# 类型是错误的。于是我把上面代码sn-p中的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# 函数..请证明我错了。

    【讨论】:

    • 是的,我只说IO-like,因为整个IO-monad 是围绕传递State# 值的概念构建的。如果您查看 GHC 中 IO monad 的实现,您会看到它被定义为 newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #)),其中右侧的 State# RealWorld -> (# State# RealWorld, a #) 看起来非常类似于 State# s -> (# State# s, a #)。因此,readIntOffAddr# 函数可以轻松提升到 IO monad。
    【解决方案2】:

    作为对迈克尔回答的补充:

    Addr#Ptr a 底层的未装箱类型,就像 Int#Int 底层的未装箱类型一样。它的内容可能被解释为机器地址,尽管就编译器和 GC 而言,它只是另一种整数类型(无论相关系统上的指针大小如何)。由于它是任意机器地址而不是 GC 管理的指针,因此它不应该指向 Haskell 堆,因为从 Haskell 级别来看,Haskell 堆对象的地址是不稳定的(GC 可能发生在您的程序,然后您的Addr# 指向的任何对象现在都存在于其他地方,或者根本不存在)。

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

    【讨论】:

    • 这为我澄清了。谢谢。
    猜你喜欢
    • 2016-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 2016-04-01
    • 2010-12-10
    • 2015-01-27
    • 2021-03-18
    相关资源
    最近更新 更多