为什么我不能将两个IntPtr与<和>?

时间:2015-04-07 06:15:22

标签: c# pointers

我目前正在使用带有不安全指针的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

3 个答案:

答案 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优先于UIntPtrhttps://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

这是从IntPtrUIntPtr

的演员表
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)

恕我直言,IntPtr并未针对诸如高/低比较之类的目标而开发。它是存储内存地址的结构,可以仅针对相等性进行测试。您不应该考虑内存中任何内容的相对位置(由CLI管理)。这就像比较Enternet中的哪个IP更高。