Weird result from unchecked(), possible compiler bug?

白昼怎懂夜的黑 提交于 2019-12-09 03:32:22

问题


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.


回答1:


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



回答2:


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.



来源:https://stackoverflow.com/questions/6883611/weird-result-from-unchecked-possible-compiler-bug

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!