13

RegOpenKeyEx当我注意到页面上的这条评论时,我正在查看 P/Invoke 声明:

更改IntPtrUIntPtr:当IntPtr为句柄调用时,您将遇到溢出。UIntPtr如果您希望它在 32 位和 64 位平台上正常工作,是正确的选择。

这对我来说没有多大意义:两者IntPtrUIntPtr应该表示指针,因此它们的大小应该与操作系统的位数相匹配——32 位或 64 位。由于这些不是数字而是指针,因此它们的带符号数值无关紧要,只有表示它们指向的地址的位。我想不出为什么这两者之间会有区别,但是这个评论让我不确定。

是否有特定的理由使用UIntPtr而不是IntPtr?根据文档

IntPtr类型符合 CLS,而类型UIntPtr不符合。只有IntPtr类型在公共语言运行时中使用。提供该UIntPtr类型主要是为了与该类型保持体系结构对称IntPtr

当然,这意味着没有区别(只要有人不尝试将值转换为整数)。那么上面来自 pinvoke.net 的评论不正确吗?

编辑

在阅读了 MarkH 的回答后,我做了一些检查,发现 .NET 应用程序不支持大地址,在 32 位模式下编译时只能处理 2GB 的虚拟地址空间。(可以使用hack来打开大地址感知标志,但 MarkH 的回答表明 .NET Framework 内部的检查会破坏事情,因为地址空间被假定为只有 2GB,而不是 3GB。)

这意味着指针可以拥有的所有正确虚拟内存地址(就 .NET Framework 而言)将介于 0x00000000 和 0x7FFFFFFF 之间。当这个范围被转换为有符号int时,没有值会是负数,因为最高位没有设置。这强化了我的信念,即使用 IntPtr 和 UIntPtr 没有区别。我的推理正确吗?

Fermat2357 指出上面的编辑是错误的。

4

3 回答 3

10

UIntPtrIntPtr在内部实现为

private unsafe void* m_value;

您都是对的,只是只管理代表地址的位。

我唯一能想到的溢出问题是如果您尝试执行指针算术。这两个类都支持添加和减去偏移量。但在这种情况下,在这种操作之后二进制表示也应该没问题。

根据我的经验,我也更喜欢UIntPtr,因为我认为指针是无符号对象。但这无关紧要,只是我的意见。

IntPtr如果您使用或UIntPtr在您的情况下,它似乎没有任何区别。

编辑:

IntPtr是符合 CLS 的,因为 CLR 之上的某些语言不支持无符号。

于 2012-11-01T05:05:43.833 回答
4

当然,这意味着没有区别(只要有人不尝试将值转换为整数)。

不幸的是,框架试图准确地做到这一点(当专门为 x86 编译时)。IntPtr(long)构造函数和方法都ToInt32()尝试将值转换为int表达式checked中的 an。这是使用框架调试符号时看到的实现。

    public unsafe IntPtr(long value)
    { 
        #if WIN32
            m_value = (void *)checked((int)value);
        #else
            m_value = (void *)value; 
        #endif
    } 

当然,如果值超出范围,检查表达式将抛出异常。相同的UIntPtr值不会溢出,因为它会尝试转换为uint

于 2012-11-01T05:43:33.020 回答
0

IntPtr\UIntPtr 之间的差异与 Int32\UInt32 之间的差异相同(即,这完全取决于如何解释数字。)

通常,您选择哪个并不重要,但如前所述,在某些情况下,它可能会回来咬您。

(我不确定为什么 MS 选择 IntPtr 以(CLS 合规性等)开头,内存作为 DWORD(u32)处理,这意味着它是无符号的,因此,首选方法应该是 UIntPtr,而不是 IntPtr,对吗? )

偶数:UIntPtr.Add()

对我来说似乎是错误的,它需要一个 UIntPtr 作为指针,以及一个“int”作为偏移量。(什么时候,对我来说,'uint' 会更有意义。为什么要将有符号值提供给无符号方法,当代码很可能将其转换为引擎盖下的 'uint' 时。/facepalm)

我个人更喜欢 UIntPtr 而不是 IntPtr 仅仅是因为无符号值与我正在使用的底层内存的值匹配。:)


顺便说一句,我最终可能会创建自己的指针类型(使用 UInt32),专门为直接使用内存而构建。(我猜 UIntPtr 不会捕获所有可能的坏内存问题,即 0xBADF00D 等,等等。这是一个等待发生的 CTD ......我将不得不看看内置类型首先处理事情,希望空\零检查正确过滤掉这样的东西。)

于 2013-06-30T09:40:34.520 回答