Вызывает ли INT_MIN% -1 неопределенное поведение? - PullRequest
24 голосов
/ 08 мая 2011

gcc генерирует плавающий код, который вызывает SIGFPE для следующего кода:

#include <limits.h>
int x = -1;
int main()
{
    return INT_MIN % x;
}

Однако в стандарте я не могу найти утверждения, что этот код вызывает неопределенное или определяемое реализацией поведение.Насколько я могу судить, требуется вернуть 0. Это ошибка в gcc или я пропустил какое-то специальное исключение, которое делает стандарт?

Ответы [ 5 ]

16 голосов
/ 08 мая 2011

Вы, вероятно, правы, что это может рассматриваться как ошибка в действующем стандарте.Текущий проект решает эту проблему:

Если частное a / b представимо, выражение (a / b) * b + a% b должно быть равно a;в противном случае поведение a / b и a% b не определено.

15 голосов
/ 08 мая 2011

Просмотр кода сборки, сгенерированного 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

9 голосов
/ 08 мая 2011
4 голосов
/ 08 мая 2011

Здесь задается тот же вопрос, что и в отчете о дефектах

http://www.open -std.org / ОТК1 / SC22 / wg21 / Docs / cwg_defects.html # 614

К сожалению, я не вижу, что в части разрешения четко указано, что он должен производить UB. Подразделение действительно будет производить UB, но для оператора % это не очевидно.

3 голосов
/ 08 мая 2011

Результат операции модуля с отрицательными операндами остается определяемым реализацией в C89, и определяется в C99 в §6.5.5 / 6:

& hellip; результат оператора / является алгебраическим частным с любой отброшенной дробной частью. 88) Если частное a/b представимо, выражение (a/b)*b + a%b должно равно a.

88) Это часто называют "усечением до нуля".

Для представления с двумя дополнениями INT_MIN / -1 равно INT_MAX + 1, поэтому он не может быть представлен как int без переноса, и я предполагаю, что реализация выберет его взрывоопасным.

...