【问题标题】:Weird result from unchecked(), possible compiler bug?unchecked() 的奇怪结果,可能的编译器错误?
【发布时间】: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:我在发布模式下抛出了一个异常,并在它抛出时附加了调试器

标签: c# casting unchecked


【解决方案1】:

太好了,我找到了。在规范的深处,有以下内容:

在未经检查的上下文中,转换始终成功,并按如下方式进行。

• 该值向零舍入到最接近的整数值。如果这个整数值在目标类型的范围内,那么这个值就是转换的结果。

否则,转换的结果是目标类型的未指定值。

就是这样。结果未定义。一切顺利。

【讨论】:

    【解决方案2】:

    来自MSDN on unchecked keyword

    在未经检查的上下文中,如果表达式产生的值是 超出目标类型的范围,结果将被截断。

    检查默认上下文,

    在检查的上下文中,如果表达式产生的值是 在目标类型范围之外,结果取决于 表达式是常量还是非常量。持续的 表达式导致编译时错误,而非常量表达式 在运行时进行评估并引发异常。

    最后,Double/Float 不会换行。

    • int.MaxValue + 1 == int.MinValue(溢出并环绕,无一例外)
    • uint.MaxValue + 1 == 0(它溢出到零,因为它是无符号的;没有抛出异常)
    • float.MaxValue + 1 == float.MaxValue(是的,运行时处理溢出,不抛出异常,但它的行为不同于 int 和 uint)
    • double.MaxValue + 1 == double.MaxValue(与浮点数相同)
    • decimal.MaxValue + 1 抛出 System.OverflowException

    【讨论】:

    • 是的,但这并不能真正解释发生了什么,是吗?事实上,unchecked((int)double.MaxValue)unchecked((int)MaxValueOfDouble) 甚至有不同的答案,其中MaxValueOfDouble 是一个设置为double.MaxValue 的变量。
    • @harold:Double.MaxValue 大于 int 可以容纳的值。
    • 是的,很明显,我对结果是 int.MinValue 或零没有任何问题,但令我烦恼的是结果因情况而异。
    • @harold:如果您要使用未检查的关键字,“结果被截断” - 可能为 0。如果未检查,它应该告诉您它超出了 int 的范围。
    • 所以我可以从中得出结论,未选中的关键字对于常量表达式和变量表达式的行为不同。我找不到任何地方说这应该是行为。
    猜你喜欢
    • 2016-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多