C# 为什么可以';比较两个IntPtr';带<;以及>;?

C# 为什么可以';比较两个IntPtr';带<;以及>;?,c#,pointers,C#,Pointers,我目前正在使用不安全的指针,这似乎是一个编译器错误 注意:问题不在于我使用的是指针和不安全代码;代码运行得很好。该问题与一个已确认的编译器bug有关,该bug在某些情况下拒绝编译合法代码。如果您对该问题感兴趣,请访问 因为我的问题是指针变量的声明,所以我决定解决这个问题,改为使用IntPtr,并在需要时转换为实际指针 然而,我注意到我不能这样做: IntPtr a = something; IntPtr b = somethingElse; if (a > b) // ERROR. Can

我目前正在使用不安全的指针,这似乎是一个编译器错误

注意:问题不在于我使用的是指针和不安全代码;代码运行得很好。该问题与一个已确认的编译器bug有关,该bug在某些情况下拒绝编译合法代码。如果您对该问题感兴趣,请访问

因为我的问题是指针变量的声明,所以我决定解决这个问题,改为使用
IntPtr
,并在需要时转换为实际指针

然而,我注意到我不能这样做:

IntPtr a = something;
IntPtr b = somethingElse;
if (a > b) // ERROR. Can't do this
{
}
似乎没有为codeIntPtr/code定义
我想我可以将codeToInt64()/code的结果转换为codeulong/code,然后进行比较,或者将codeIntPtr/code转换为指针,然后进行比较,但这让我想,为什么code>
IntPtr
一直被忽视了。在.NET 4.0之前,甚至没有
添加
/
运算符+
减法
/
运算符-

现在。。。如果要比较两个指针,请将它们转换为
long
(如果它们是
IntPtr
),或转换为
ulong
(如果它们是
UIntPtr
)。请注意,在Windows上,只有在使用带有
/3GB
选项的32位程序时,才需要
UIntPtr
,因为否则32位程序只能使用较低的2gb地址空间,而对于64位程序,使用的地址空间远小于64位(此时)

显然,如果您在.NET中进行内核编程,则会发生以下变化:-)(我希望:-)我在这里参加比赛

鉴于
IntPtr
优于
UIntPtr
的原因:

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

有些语言不区分有符号类型和无符号类型。NET希望支持他们

使用

editbin /LARGEADDRESSAWARE myprogram.exe
(我甚至可以使我的图形适配器崩溃:-)

注意,由于符号扩展的工作方式,您不能简单地执行
(uintpttr)(ulong)(long)ptr
,因为在32位时它将中断


但请注意,很少有程序真正支持32位大于2GB的数据

IMHO,IntPtr并不是为高/低比较等目的而开发的。它是一种存储内存地址的结构,只能进行相等性测试。你不应该考虑任何事物在内存中的位置(这是CLI管理的)。这就像比较Enternet中哪个IP更高。

比较IntPtr非常非常危险。C语言不允许这样做的核心原因,即使CLR对此没有问题

IntPtr经常用于存储非托管指针值。最大的问题是:指针值不是有符号的值。只有UIntPtr是存储它们的适当托管类型。UIntPtr的一个大问题是它不是一个符合CLS的类型。许多语言不支持无符号类型。Java、JScript和VB.NET的早期版本就是例子。因此,所有框架方法都使用IntPtr

它特别令人讨厌,因为它经常毫无问题地工作。从32位版本的Windows开始,地址空间的上限2GB保留给操作系统,因此程序中使用的所有指针值始终为0x8000000。现在IntPtr比较在完全随机的情况下失败了。例如,0x80000100的值实际上大于0x7FFFFFE00,但比较结果表明它更小。不好的。而且这种情况并不经常发生,指针值往往是相似的。它是非常随机的,实际的指针值是高度不可预测的

这是一个没有人能诊断的错误


使用C或C++的程序员也很容易犯这个错误,他们的语言并不能阻止他们。微软想出了另一种方法来避免这种痛苦,这种程序必须与特定的链接才能获得超过2GB的地址空间。

请注意,
IntPtr
是有符号的,因此最终它相当于
int
long
。如果您想让它不签名,请使用
UIntPtr
@xanatos:我不太确定。我认为
IntPtr
是一个内部带有
void*
的结构。我可以完美地比较
void*
,因此我认为实际的不安全指针在CLR中没有签名。不幸的是,大多数与内存相关的函数,如
marshall.AllocHGlobal()
返回
IntPtr
,而不是
UIntPtr
。我想知道为什么有两种不同的类型,一个指针就是一个指针就是一个指针IntPtr@PandaPajama:“我可以完美地比较空虚”*-也许,有点。如果它们指向同一个对象,或者指向同一数组中的元素,或者指向同一数组末尾的元素,则可以进行这样的比较。否则,比较
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));
        }
    }
}
public static UIntPtr IntPtrToUintPtr(IntPtr ptr)
{
    if (IntPtr.Size == 4)
    {
        return unchecked((UIntPtr)(uint)(int)ptr);
    }

    return unchecked((UIntPtr)(ulong)(long)ptr);
}