3

从 FW 4.0 开始,该IntPtr结构具有以下Add方法:

public static IntPtr Add(
    IntPtr pointer,
    int offset
)

太好了,因为它应该解决IntPtr我们遇到的所有数学问题(12,可能更多)。

但为什么是offset int
一定不是IntPtr吗?我可以很容易地想象将 64 位指针偏移一个超出int范围的值。


例如,考虑Marshal.OffsetOf

public static IntPtr OffsetOf(
    Type t,
    string fieldName
)

它返回一个IntPtr作为结构成员的偏移量。这很有意义!并且您不能轻松地将此偏移量与新Add方法一起使用。您必须将其转换为Int64,然后Add在循环中多次调用。

此外,它似乎扼杀了IntPtr.Size与正确编写的应用程序无关的想法。您必须将偏移量转换为特定类型,例如Int64,此时您必须开始管理大小差异。想象一下当 128 位IntPtr出现时会发生什么。


我的问题是,为什么?
我的结论是正确的,还是我错过了重点?

4

2 回答 2

5

它对应于 x64 架构中的限制。相对寻址仅限于带符号的 32 位偏移值。Matt Pietrek 在这篇文章中提到了这一点(在“幸运的是,答案是否定的”附近)。此限制还解释了为什么 .NET 对象在 64 位模式下仍被限制为 2GB。同样,在本机 x64 C/C++ 代码中,内存分配也是有限的。并不是不可能,位移可以存储在 64 位寄存器中,只是这会使数组索引变得更加昂贵。

Marshal.OffsetOf() 的神秘返回类型可能是一个极端情况。在应用大于 2GB 的 [StructLayout] 和 [MarshalAs] 后,托管结构可能会导致非托管版本。

是的,这不能很好地映射到一些未来的 128 位架构。但是,当没有人知道它会是什么样子时,要为今天的软件准备拱门是非常困难的。也许这句老话适合,16 TB 对任何人来说都应该足够了。而且还有很大的增长空间,2^64 是一个相当大的数字。当前的 64 位处理器仅实现 2^48。在机器离得那么近之前,需要解决一些非常重要的问题。

于 2010-11-24T14:40:16.097 回答
1

如果您仅定义:

public static IntPtr Add(IntPtr pointer, IntPtr offset)

那么,恕我直言,将 32 位偏移量添加到 64 位指针的可读性较差。

同样,如果你定义

public static IntPtr Add(IntPtr pointer, long offset)

然后,将 64 位偏移量添加到 32 位指针也是不好的。

顺便说一句,Substract返回一个 IntPtr,因此 IntPtr 逻辑无论如何都不会被破坏。

于 2010-11-24T14:13:18.783 回答