Подтвердить что ты не робот

Выполняет ли INT_MIN% -1 поведение undefined?

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

Взгляд на код сборки, сгенерированный 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

Ответ 4

Тот же вопрос задается здесь как Отчет о дефектах

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#614

К сожалению, я не вижу, чтобы он прямо заявил в части резолюции, что он должен производить UB. Деление действительно произведет UB, но для оператора % это не очевидно.

Ответ 5

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

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

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

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