Выражение int.Minvalue / -1
приводит к определенному поведению в соответствии со спецификацией С#:
7.8.2 Оператор дивизиона
Если левый операнд является наименьшим представимым значением int или long, а правый операнд равен -1, происходит переполнение. В проверенном контексте это вызывает System.ArithmeticException(или его подкласс). В неконтролируемый контекст, определяется в отношении того, является ли Исключение System.ArithmeticException(или его подкласс) или переполнение не сообщается с результирующим значением, равным левый операнд.
Программа тестирования:
var x = int.MinValue;
var y = -1;
Console.WriteLine(unchecked(x / y));
Это выдает OverflowException
на .NET 4.5 32bit, но это не обязательно.
Почему спецификация оставляет решение, определяемое результатом? Здесь дело против этого:
- Инструкция x86
idiv
всегда приводит к исключению в этом случае. - На других платформах может потребоваться проверка времени выполнения, чтобы подражать этому. Но стоимость этой проверки была бы низкой по сравнению со стоимостью подразделения. Целочисленное деление чрезвычайно дорого (15-30 циклов).
- Это открывает риски совместимости ( "write once run никуда" ).
- Презентация разработчика.
Также интересен тот факт, что если x / y
является константой компилятора, мы действительно получаем unchecked(int.MinValue / -1) == int.MinValue
:
Console.WriteLine(unchecked(int.MinValue / -1)); //-2147483648
Это означает, что x / y
может иметь различное поведение в зависимости от используемой синтаксической формы (и не только в зависимости от значений x
и y
). Это допускается спецификацией, но это кажется неразумным выбором. Почему С# был создан так?
A аналогичный вопрос указывает, где в спецификации это точное поведение предписано, но оно (недостаточно) не отвечает, почему язык был разработан таким образом. Альтернативные варианты не обсуждаются.