【发布时间】:2012-10-21 16:04:53
【问题描述】:
当我注意到页面上的这条评论时,我正在查看RegOpenKeyEx 的 P/Invoke 声明:
将
IntPtr更改为UIntPtr:使用IntPtr调用句柄时,您将遇到溢出。如果您希望它在 32 位和 64 位平台上正常工作,UIntPtr是正确的选择。
这对我来说没有多大意义:IntPtr 和 UIntPtr 都应该表示指针,因此它们的大小应该与操作系统的位数相匹配 - 32 位或 64 位。由于这些不是数字而是指针,因此它们的带符号数值无关紧要,只有表示它们指向的地址的位。我想不出这两者之间会有什么不同的任何原因,但这个评论让我不确定。
使用UIntPtr 代替IntPtr 是否有特定原因?根据documentation:
IntPtr类型符合 CLS,而UIntPtr类型不符合。在公共语言运行库中仅使用IntPtr类型。提供UIntPtr类型主要是为了与IntPtr类型保持架构对称。
当然,这意味着没有区别(只要有人不尝试将值转换为整数)。那么上面来自pinvoke.net的评论不正确吗?
编辑:
阅读MarkH's answer后,我做了一些检查,发现.NET应用程序不能识别大地址,在32位模式下编译时只能处理2GB的虚拟地址空间。 (可以使用hack 来打开大地址感知标志,但 MarkH 的回答表明 .NET Framework 内部的检查会破坏事情,因为假定地址空间只有 2GB,而不是 3GB。)
这意味着指针可以拥有的所有正确的虚拟内存地址(就 .NET Framework 而言)将介于 0x00000000 和 0x7FFFFFFF 之间。当此范围转换为带符号的int 时,没有值会是负数,因为最高位未设置。这强化了我的信念,即使用 IntPtr 和 UIntPtr 没有区别。我的推理正确吗?
Fermat2357指出上面的编辑是错误的。
【问题讨论】:
-
@Fermat2357 是的,正是这个问题促使我输入了一个新问题。
-
我认为你是对的。完全没有区别。
HANDLE只是资源的唯一编号(当然在 Win32 中它通常实现为指向内存区域的 32 位指针)。但是,IntPtr能够嵌入任何类型的 32 位数字。与 UIntPtr 的区别只是对这个数字的解释而已。