IntPtr和UIntPtr之间的区别

时间:2012-11-01 04:05:30

标签: c# .net pointers intptr

当我在页面上发现此评论时,我正在查看RegOpenKeyEx的P / Invoke声明:

  

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

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

使用UIntPtr代替IntPtr是否有特定原因?根据{{​​3}}:

  

IntPtr类型符合CLS,而UIntPtr类型则不符合。公共语言运行库中仅使用IntPtr类型。提供UIntPtr类型主要是为了保持IntPtr类型的架构对称性。

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

修改

在阅读documentation之后,我做了一些检查,发现.NET应用程序不是大地址感知,并且在32位模式下编译时只能处理2GB的虚拟地址空间。 (可以使用MarkH's answer打开大地址识别标志,但MarkH的答案显示.NET Framework内的检查会破坏因为地址空间仅为2GB,而不是3GB。)

<击>

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

Fermat2357指出上述编辑错误。

3 个答案:

答案 0 :(得分:9)

UIntPtrIntPtr内部实施为

private unsafe void* m_value;

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

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

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

如果您在案件中使用IntPtrUIntPtr,似乎没有任何区别。

编辑:

IntPtr符合CLS,因为CLR之上的语言不支持unsigned。

答案 1 :(得分:4)

  

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

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

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

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

答案 2 :(得分:0)

IntPtr \ UIntPtr之间的差异与以下各项之间的差异相同:Int32 \ UInt32(即,所有这些都是关于如何解释数字的。)

通常情况下,选择哪个并不重要,但正如所提到的,在某些情况下,它可能会再次咬你。

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

Even:UIntPtr.Add()

对我来说似乎不对,它需要一个UIntPtr作为指针,而一个'int'作为偏移量。 (对我来说,'uint'会更有意义。为什么将一个有符号的值输入到一个无符号方法中,当代码很可能将它转换为'uint'时。/ facepalm)

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


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