Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.4k views
in Technique[技术] by (71.8m points)

c# - Weird result from unchecked(), possible compiler bug?

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...