unchecked() 的奇怪结果,可能是编译器错误吗?

发布于 2024-11-27 08:45:57 字数 881 浏览 1 评论 0原文

以下代码段的计算结果为零:

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。对我来说,这仍然像是编译器错误。

The following snippet evaluates to zero:

int result = unchecked((int)double.MaxValue);

Whereas, if you do this:

double x = double.MaxValue
int result = (int)x;

The result is (would you even guess this?) int.MinValue. That fact alone is weird enough[see below], but I was under the impression that unchecked was meant to force the compiler into emitting code that pretends not to know that a conversion will definitely fail and/or some overflow happens. In other words, it should give the same result as when the compiler has no knowledge of the values involved (assuming it is compiled with "Check for arithmetic overflow" disabled)

So, what's going on here? Is my understanding of unchecked wrong?

Is one of the results "wrong", as per the C#/.NET standard?


edit: the int.MinValue is explained easily enough: cvttsd2si gives 0x80000000 when there would have been overflow but the exception is masked. That's the instruction used by the JIT compiler, as can be seen in the disassembly window. That doesn't solve any part of the issue though.


According to ECMA 334 (C# 2 spec), the unchecked keyword should always truncate and therefore the result should be zero in both of these cases:

int result1 = unchecked((int)double.MaxValue);
double x = double.MaxValue;
int result2 = unchecked((int)x);

But it isn't, the second one gives int.MinValue. This still smells like compiler bug to me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半世晨晓 2024-12-04 08:45:57

来自 MSDN 上未经检查的关键字

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

检查默认上下文,

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

最后,Double/Float 不换行。

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

From MSDN on unchecked keyword,

In an unchecked context, if an expression produces a value that is
outside the range of the destination type, the result is truncated.

The default context is checked,

In a checked context, if an expression produces a value that is
outside the range of the destination type, the result depends on
whether the expression is constant or non-constant. Constant
expressions cause compile time errors, while non-constant expressions
are evaluated at run time and raise exceptions.

Finally, Double/Float does not wrap.

  • int.MaxValue + 1 == int.MinValue (it overflows and wraps around with no exception)
  • uint.MaxValue + 1 == 0 (it overflows to zero since it is unsigned; no exception thrown)
  • float.MaxValue + 1 == float.MaxValue (yes, the runtime handles the overflow, no exception is thrown, but it behaves differently tha int and uint)
  • double.MaxValue + 1 == double.MaxValue (same as float)
  • decimal.MaxValue + 1 throws a System.OverflowException
給妳壹絲溫柔 2024-12-04 08:45:57

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

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

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

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

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

Great, I found it. Buried deep inside the spec, there is a the following:

In an unchecked context, the conversion always succeeds, and proceeds as follows.

• The value is rounded towards zero to the nearest integral value. If this integral value is within the range of the destination type, then this value is the result of the conversion.

Otherwise, the result of the conversion is an unspecified value of the destination type.

So that's it. The result is undefined. Everything goes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文