【发布时间】:2011-10-16 13:13:44
【问题描述】:
以下 sn-p 的计算结果为零:
int result = unchecked((int)double.MaxValue);
然而,如果你这样做:
double x = double.MaxValue
int result = (int)x;
结果是(你能猜到吗?)int.MinValue。这个事实本身就很奇怪[见下文],但我的印象是unchecked 旨在强制编译器发出假装不知道转换肯定会失败和/或发生一些溢出的代码。换句话说,它应该给出与编译器不知道所涉及的值时相同的结果(假设它是在禁用“检查算术溢出”的情况下编译的)
那么,这里发生了什么?难道我对unchecked的理解错了吗?
根据 C#/.NET 标准,其中一个结果是否“错误”?
编辑:int.MinValue 很容易解释:cvttsd2si 在溢出但异常被屏蔽时给出 0x80000000。这是 JIT 编译器使用的指令,可以在反汇编窗口中看到。但这并不能解决问题的任何部分。
根据 ECMA 334(C# 2 规范),unchecked 关键字应始终截断,因此在这两种情况下结果都应为零:
int result1 = unchecked((int)double.MaxValue);
double x = double.MaxValue;
int result2 = unchecked((int)x);
但不是,第二个给出了int.MinValue。这对我来说仍然像编译器错误。
【问题讨论】:
-
我冒险猜测一下,说这与 double 和 int 类型的二进制表示有关。
-
@Jon Grant:我对此表示怀疑,0x80000000 是 -0 作为浮点数(而不是双精度的正确大小)。但是,cvttsd2si 指定 0x80000000 是当 double 太大并屏蔽溢出异常时的结果。这就是
int.MinValue的来源,但是零呢? -
请记住这一点,当您认为这是编译器错误时,它不是 - 这是您的代码或理解。仅供参考
-
你看的不是真正的代码,这些表达式是由抖动评估的。工具+选项,调试,常规,取消勾选“抑制JIT优化”选项。抖动不会发出任何代码来尝试规范溢出行为,它太昂贵了。
-
@Hans Passant:我在发布模式下抛出了一个异常,并在它抛出时附加了调试器