【发布时间】:2017-09-22 11:54:21
【问题描述】:
考虑这段代码:
IntPtr p = (IntPtr) (long.MaxValue); // Not a valid ptr in 32 bit,
// but this is to demonstrate the exception for 64 bit
Console.WriteLine((int)(long)p);
Console.WriteLine((int)p);
当在 64 位上编译和运行时,第二个 WriteLine 会抛出 OverflowException。这记录在here。
我的问题是:为什么?
当将指针转换为Int32 时,您在概念上会丢失所有指针语义,并在语义上将指针简化为整数表示。那为什么要抛出异常,而不是截断值以适合整数呢?恕我直言,那将是最明智的做法。因为如果程序员真的想不惜一切代价避免截断,为什么首先将其放入 int 中?
这种设计是故意的,还是转换运算符的不完整实现?
在阅读了第一个 cmets 之后,我觉得有必要进行一些澄清。我的问题也可以这样解读:
是否有一个实际的用例,您可以将IntPtr 放入int,然后再将其转换回IntPtr,这样之后它仍然有效?
作为对询问用例的人们的回复,让我给出我能想到的将IntPtr 放入int 的唯一用例:实现GetHashCode for a managed wrapper object around an unmanaged对象。
【问题讨论】:
-
如何截断指针明智?如果你真的想要这个,你总是可以明确地做到这一点。您应该感谢默认情况是检测这种情况并抛出异常,无论您认为从哲学角度来看什么是最吸引人的。请注意,转换指针的最常见原因是 不 在某种真空中欣赏它的位 - 这是因为最终值将被转换回来,可能是在操作之后。当价值被冲走时,祝你好运。
-
您正试图将 64 磅的猪塞进 32 磅的戳中。它当然溢出了戳。转换为 long 仅有助于在没有尖叫声的情况下将猪减掉 32 磅,如果表达式为
unchecked,则截断是无声的。默认情况下,没有足够的程序员更改的项目设置顺便说一句。自 Windows 8.1 以来,这种溢出尤其常见,他们倾向于分配 4 GB 以上的内存。 -
请注意,如果您在编译时启用溢出检查,即使对于常规整数,使用强制转换将 64 位值截断为 32 位也会失败。截断不是应该“在所有情况下”都起作用的东西。通过显式屏蔽位,它总是可以使工作。显式是一件好事,但尤其是当您丢弃指针的位时。
-
在 .Net 4 之前的 .Net 版本中,除了通过
int之外,您不能进行指针运算,这是不正确的。您始终可以将long与IntPtr一起使用,并且您'一直能够在unsafe代码中使用实际指针。 -
@MatthewWatson:关键是,对于 32 位代码,通过转换为
int来进行指针运算至少是合理的。 (避免unsafe代码有不相关的原因,比如需要更高的信任度。)当然,谨慎的开发人员不会仅仅因为他们知道他们今天的代码是 32 位而使用 32 位类型,但开发人员并不谨慎.并且还痴迷于性能。尤其是那些围绕指针投射的。