int y = -2147483648;
int z = unchecked(y / -1);
Вторая строка вызывает ошибку OverflowException
. Разве unchecked
не должен этому помешать?
Например:
int y = -2147483648;
int z = unchecked(y * 2);
не вызывает исключения.
int y = -2147483648;
int z = unchecked(y / -1);
Вторая строка вызывает ошибку OverflowException
. Разве unchecked
не должен этому помешать?
Например:
int y = -2147483648;
int z = unchecked(y * 2);
не вызывает исключения.
Это не исключение, над которым компилятор C# или джиттер имеют какой-либо контроль. Это характерно для процессоров Intel/AMD, ЦП генерирует ловушку #DE (ошибка деления) при сбое инструкции IDIV. Операционная система обрабатывает ловушку процессора и отражает ее обратно в процесс с исключением STATUS_INTEGER_OVERFLOW. CLR добросовестно преобразует его в соответствующее управляемое исключение.
Руководство по процессору Intel не является золотым рудником информации об этом:
Нецелочисленные результаты усекаются (отрезаются) в сторону 0. Остаток всегда меньше делителя по величине. Переполнение обозначается исключением #DE (ошибка деления), а не флагом CF.
На английском языке: результат деления со знаком равен +2147483648, что не может быть представлено в int, так как это Int32.MaxValue + 1. В противном случае это неизбежный побочный эффект того, как процессор представляет отрицательные значения, это использует кодировку с дополнением до двух. Что создает одно значение для представления 0, оставляя нечетное количество других возможных кодировок для представления отрицательных и положительных значений. Есть еще один для отрицательных значений. Тот же вид переполнения, что и -Int32.MinValue
, за исключением того, что процессор не перехватывает инструкцию NEG и просто выдает результат "мусор".
Язык C#, конечно, не единственный с этой проблемой. Спецификация языка C# делает поведение, определяемое реализацией (глава 7.8.2), отмечая особое поведение. Никакой другой разумной вещи, которую они могли бы сделать с этим, генерация кода для обработки исключения, безусловно, считалась слишком непрактичной, производя недиагностируемый медленный код. Не в стиле С#.
Язык C и C++ специфицирует анте, делая его поведение неопределенным. Это может быть действительно уродливым, как программа, скомпилированная с помощью компилятора gcc или g++, обычно с набором инструментов MinGW. Который имеет несовершенную поддержку SEH во время выполнения, он проглатывает исключение и позволяет процессору перезапустить инструкцию деления. Программа зависает, сжигая ядро на 100%, а процессор постоянно генерирует ловушки #DE. Превращение деления в легендарную инструкцию "Остановись и гори" :)
unchecked
. Тот факт, что C# повторно выдает ошибку, когда ее выдает процессор, на самом деле ничего не объясняет.
- person Servy; 27.10.2014
unchecked
заключается в том, чтобы не генерировать исключения переполнения при переполнении целочисленной операции, а скорее в переносе.
- person Servy; 27.10.2014
neg
на -2147483648 не мусор, на самом деле это +2147483648 (при интерпретации без знака)
- person harold; 29.10.2014
Раздел 7.72 (оператор деления) спецификаций С# 4 гласит:
Если левый операнд является наименьшим представимым целым или длинным значением, а правый операнд равен –1, происходит переполнение. В проверенном контексте [...]. В непроверенном контексте определяется реализацией в отношении того, будет ли выброшено исключение System.ArithmeticException (или его подкласс) или о переполнении не будет сообщено, а результирующее значение будет значением левого операнда.
Таким образом, тот факт, что это вызывает исключение в непроверенном контексте, на самом деле не является ошибкой, поскольку поведение определяется реализацией.
int.MinValue
. При написании этого кода на C# вам действительно нужно предполагать, что он может иметь любое поведение, вы даже не можете предположить, что он вызовет исключение.
- person Servy; 27.10.2014
int
или long
, а правый операнд равен –1
, происходит переполнение. В этой ситуации всегда выдается System.OverflowException
, независимо от того, происходит ли операция в контексте checked
или unchecked
.
- person Dmitry; 27.10.2014
y
на const
, деление, конечно же, будет выполняться во время компиляции. И текущая реализация компилятора C# позволяет это (учитывая, что вы сохраняете ключевое слово unchecked
явным); нет ошибки времени компиляции. Итак, у вас есть ситуация, когда удаление модификатора const
изменит результат программы. Компилятор C# и среда выполнения не согласны с тем, как делить целые числа.
- person Jeppe Stig Nielsen; 28.10.2014
Согласно разделу 7.8.2 Спецификации языка C# 5.0 имеем следующий случай:
7.8.2 Оператор деления
Для операции формы x / y применяется разрешение перегрузки бинарного оператора (§7.3.4) для выбора конкретной реализации оператора. Операнды преобразуются в типы параметров выбранного оператора, а тип результата является типом возвращаемого значения оператора. Предопределенные операторы деления перечислены ниже. Все операторы вычисляют частное x и y.
- Целочисленное деление:
int operator /(int x, int y);
uint operator /(uint x, uint y);
long operator /(long x, long y);
ulong operator /(ulong x, ulong y);
Если значение правого операнда равно нулю, выдаетсяSystem.DivideByZeroException
. При делении результат округляется до нуля. Таким образом, абсолютное значение результата — это максимально возможное целое число, меньшее или равное абсолютному значению частного двух операндов. Результат равен нулю или положителен, если два операнда имеют одинаковый знак, и равен нулю или отрицателен, если два операнда имеют противоположные знаки. Если левый операнд является наименьшим представимым целым или длинным значением, а правый операнд равен –1, возникает переполнение. В проверенном контексте это вызывает выбросSystem.ArithmeticException
(или его подкласса). В непроверенном контексте реализация определяет, будет ли выброшенSystem.ArithmeticException
(или его подкласс) или о переполнении не будет сообщено, а результирующее значение будет значением левого операнда.
unchecked
позволяет избежать исключений переполнения, C# должен был бы генерировать код вокруг каждого непроверенного деления, чтобы проверить этот конкретный случай перед вызовомidiv
— это замедлило бы деление в непроверенных контекстах, что было бы довольно неинтуитивно, посколькуunchecked
должен < i>удалить дополнительные проверки и улучшить производительность.. - person Blorgbeard   schedule 27.10.2014unchecked
не упоминается C#, но вместо этого упоминаетсяjavac
- возможно, было бы неплохо обновить отрывок из тега или убрать его из этого вопроса (я не могу этого сделать, поскольку никогда не использовал ключевое слово unchecked). Точно так жеchecked
относится к HTML... - person Thomas   schedule 28.10.2014