我目前正在使用带有不安全指针的a problem,这似乎是一个编译器错误。
注意:问题不在于我使用的是指针和不安全的代码;代码工作得很好。该问题与确认的编译器错误有关,该错误在某些情况下拒绝编译法律代码。如果您对该问题感兴趣,请访问my other question
由于我的问题在于指针变量的声明,我决定解决这个问题,而是使用IntPtr
代替,并在需要时转换为实际的指针。
然而,我注意到我不能做这样的事情:
IntPtr a = something;
IntPtr b = somethingElse;
if (a > b) // ERROR. Can't do this
{
}
似乎没有为>
定义<
和IntPtr
运算符。请注意,我确实可以比较两个实际指针。
IntPtr
有.ToInt64()
方法。但是,这会返回签名的值,在与>
和<
进行比较时,如果涉及正值和负值,则可能会返回错误的值。
说实话,我并不真正理解.ToInt64()
方法对于返回已签名值的方法有何用处,考虑到pointer comparisons are performed unsigned,但这不是我的问题。
有人可能会说IntPtr
是不透明的句柄,因此与>
和<
进行比较毫无意义。但是,我要指出IntPtr
有加法和减法方法,这意味着IntPtr
实际上存在订单概念,因此>
和<
确实存在有意义。
我想我可以将ToInt64()
的结果转换为ulong
然后比较,或者将IntPtr
转换为指针,然后进行比较,但这让我想到为什么>
未定义<
和IntPtr
。
为什么我不能直接比较两个IntPtr
?
答案 0 :(得分:6)
IntPtr
一直有点被忽视。直到.NET 4.0,甚至Add
/ operator+
和Subtract
/ operator-
都没有。
现在......如果你想比较两个指针,如果它们是long
,则将它们转换为IntPtr
,如果它们是ulong
,则转换为UIntPtr
。请注意,在Windows上,只有在使用带有UIntPtr
选项的32位程序时才需要/3GB
,否则32位程序只能使用较低的2gb地址空间,而对于64位程序,使用的地址空间少于64位(此时为48 bits)。
显然如果你在.NET中进行内核编程,这会改变:-)(我在这里jocking,希望:-))
为什么IntPtr
优先于UIntPtr
:https://msdn.microsoft.com/en-us/library/system.intptr%28v=vs.110%29.aspx
IntPtr类型符合CLS,而UIntPtr类型则不符合。在公共语言运行库中仅使用IntPtr类型。提供UIntPtr类型主要是为了保持IntPtr类型的架构对称性。
有些语言不区分有符号和无符号类型。 .NET希望支持它们。
使用
完成一些测试editbin /LARGEADDRESSAWARE myprogram.exe
(我甚至可以崩溃我的图形适配器:-))
static void Main(string[] args)
{
Console.WriteLine("Is 64 bits", Environment.Is64BitProcess);
const int memory = 128 * 1024;
var lst = new List<IntPtr>(16384); // More than necessary
while (true)
{
Console.Write("{0} ", lst.Count);
IntPtr ptr = Marshal.AllocCoTaskMem(memory);
//IntPtr ptr = Marshal.AllocHGlobal(memory);
lst.Add(ptr);
if ((long)ptr < 0)
{
Console.WriteLine("\nptr #{0} ({1}, {2}) is < 0", lst.Count, ptr, IntPtrToUintPtr(ptr));
}
}
}
我能够使用32位程序(在64位操作系统上)分配近4 GB的内存(所以我有负IntPtr
)
这是从IntPtr
到UIntPtr
public static UIntPtr IntPtrToUintPtr(IntPtr ptr)
{
if (IntPtr.Size == 4)
{
return unchecked((UIntPtr)(uint)(int)ptr);
}
return unchecked((UIntPtr)(ulong)(long)ptr);
}
请注意,由于符号扩展的工作原理,您不能简单地执行(UIntPtr)(ulong)(long)ptr
,因为在32位时它会中断。
但请注意,很少有程序支持&gt; 32位上2 gb ... http://blogs.msdn.com/b/oldnewthing/archive/2004/08/12/213468.aspx
答案 1 :(得分:2)
比较IntPtr是非常非常危险的。 C#语言不允许这样做的核心原因,即使CLR没有问题。
IntPtr经常用于存储非托管指针值。最大的问题是:指针值不是有符号值。只有UIntPtr才是存储它们的适当托管类型。 UIntPtr的一个大问题是它不是符合CLS的类型。许多语言不支持无符号类型。 Java,JScript和早期版本的VB.NET就是例子。因此,所有框架方法都使用IntPtr。
它特别令人讨厌,因为它经常没有问题。从32位版本的Windows开始,地址空间的高2 GB保留给操作系统,因此程序中使用的所有指针值始终为&lt; = 0x7FFFFFFFF。在IntPtr中工作正常。
但在每种情况下都不是这样。您可以在64位操作系统上的wow64模拟器中作为32位应用程序运行。操作系统不再需要高2 GB的地址空间,因此您可以获得4 GB的地址空间。这是非常好的,32位代码经常围绕着OOM。指针值现在执行获取&gt; = 0x80000000。现在IntPtr比较在完全随机的情况下失败了。例如,0x80000100的值 大于0x7FFFFE00,但比较会说它更小。不好。它并不经常发生,指针值往往相似。并且它是随机的,实际指针值非常难以预测。
这是一个没人能诊断的错误。
使用C或C ++的程序员也很容易犯这个错误,他们的语言并没有阻止它们。微软提出了另一种避免这种痛苦的方法,这样的程序必须与特定的linker option链接才能获得超过2 GB的地址空间。
答案 2 :(得分:0)