Странный результат от unchecked (), возможная ошибка компилятора? - PullRequest
9 голосов
/ 30 июля 2011

Следующий фрагмент оценивается как ноль:

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

Принимая во внимание, что если вы сделаете это:

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

В результате (вы даже догадались бы?) int.MinValue.Уже один этот факт достаточно странный [см. Ниже], но у меня сложилось впечатление, что unchecked предназначался для того, чтобы заставить компилятор выдавать код, который делает вид, что не знает, что преобразование обязательно завершится неудачей и / или произойдет некоторое переполнение.Другими словами, он должен давать тот же результат, что и когда компилятор ничего не знает о задействованных значениях (при условии, что он скомпилирован с отключенной «проверкой на арифметическое переполнение»)

Итак, что здесь происходит?Неужели мое понимание unchecked неверно?

Является ли один из результатов "неправильным" в соответствии со стандартом C # /. NET?


edit: объяснен 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.Это все еще пахнет как ошибка компилятора для меня.

Ответы [ 2 ]

4 голосов
/ 30 июля 2011

С 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)
  • десятичный. MaxValue + 1 создает исключение System.OverflowException
3 голосов
/ 30 июля 2011

Отлично, я нашел это. Глубоко в спецификации есть следующее:

В неконтролируемом контексте преобразование всегда завершается успешно и выполняется следующим образом.

• Значение округляется от нуля до ближайшего целого значения. Если это интегральное значение находится в диапазоне типа назначения, то это значение является результатом преобразования.

В противном случае результатом преобразования является неопределенное значение типа назначения.

Вот и все. Результат не определен. Все идет.

...