Просмотр кода сборки, сгенерированного gcc (x определен как -1 ранее в сборке):
movl x, %ecx
movl $-2147483648, %eax
movl %eax, %edx
sarl $31, %edx
idivl %ecx
Первая вычислительная инструкция, sarl
, сдвиг вправо -2147483648
31 бит.Это приводит к -1
, который помещается в %edx
.
Далее idivl
выполняется.Это подписанная операция.Позвольте мне процитировать описание:
Делит содержимое двойного слова, содержащегося в комбинированных регистрах% edx:% eax, на значение в указанном регистре или ячейке памяти.
Итак, -1:-2147483648 / -1
- это разделение, которое происходит.-1:-2147483648
интерпретируется как двойное слово, равное -2147483648
(на машине дополнения до двух).Теперь -2147483648 / -1
происходит, что возвращает 2147483648
.БУМ!Это еще один INT_MAX
.
Вопрос о том, почему это ошибка в gcc, или я пропускаю какое-то специальное исключение, которое делает стандарт?
В стандарте C99 этоявляется неявным UB (§6.5.5 / 6):
… результатом оператора / является алгебраический фактор, при котором любая дробная часть отбрасывается.88) Если фактор a / b представим,выражение (a / b) * b + a% b должно равняться a.
INT_MIN / -1
не может быть представлено, поэтому это UB.
В C89, однако оператор%Реализация определена, и является ли это ошибкой компилятора или нет, может быть обсуждено.Однако проблема указана на gcc: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30484