Вычитается ли INT_MIN из любого целого числа, которое считается неопределенным поведением?

Что, если у меня есть что-то вроде этого:

int a = 20;
int min = INT_MIN;

if(-a - min)
//do something

Предположим, что INT_MIN, если оно положительное, больше, чем INT_MAX. Будет ли min компилятор когда-либо преобразовывать что-то вроде -min как в -INT_MIN, которое может быть неопределенным?


person user2672807    schedule 25.09.2013    source источник
comment
возможный дубликат недополнения и переполнения C++   -  person Jonathan Potter    schedule 26.09.2013
comment
Идентификатор min имеет неплохую вероятность затенения std::min (когда есть оператор using), поэтому я бы не рекомендовал его использовать.   -  person Brian Cain    schedule 26.09.2013
comment
@JonathanPotter Я думаю, что ОП этого вопроса прекрасно понимает, что знаковое арифметическое переполнение не определено (что является ответом на предложенный вами вопрос), и просто обеспокоено тем, что явно определенное двоичное вычитание может быть интерпретировано как неопределенный унарный минус.   -  person Pascal Cuoq    schedule 26.09.2013
comment
@Brian Я использую using namespace std;, но я не понимаю, как будет вызываться min(), если я не использую круглые скобки.   -  person user2672807    schedule 26.09.2013
comment
@ user2672807: он не сказал, что будет вызываться min, он сказал, что ваша переменная затеняет его. Поэтому, если вы попытаетесь вызвать min без уточнения, вы не сможете это сделать, потому что min означает int, а не функцию.   -  person Steve Jessop    schedule 26.09.2013
comment
@ Стив, я согласен с этим, но считается ли это плохой практикой?   -  person user2672807    schedule 26.09.2013
comment
@ user2672807: кем считается плохим? В этом случае это довольно безопасно, потому что вы не можете вызвать int — скрытие стандартной функции с помощью функции было бы более рискованным. Лично я считаю, что using namespace std; хуже, чем скрытие имени, поэтому вопрос о неожиданном сокрытии не должен возникать с самого начала.   -  person Steve Jessop    schedule 26.09.2013
comment
@BrianCain - идентификатор min не конфликтует с std::min в правильно написанном коде; вот почему у нас есть пространства имен. Сдувать их с помощью using namespace std; — мерзость.   -  person Pete Becker    schedule 26.09.2013
comment
@PeteBecker, мир усеян неправильно написанным кодом. Мерзость или нет, такое случается, и моя рекомендация остается в силе.   -  person Brian Cain    schedule 26.09.2013
comment
@BrianCain - using namespace std; просто неправильно, и лучшая защита от этого - не делать этого. Учитывая выбор не использовать min в качестве имени и не использовать using namespace std;, последнее, очевидно, лучше. Особенно, когда проблема не в том, что min конфликтует с std::min, а в том, что если вы используете min в качестве имени переменной, и вы вызываете std::min без квалификатора, вы получите ошибку. Эту ошибку легко исправить; если вы не можете заставить себя удалить using namespace std;, добавьте квалификатор к min там, где он вызывается.   -  person Pete Becker    schedule 26.09.2013
comment
@PeteBecker, я думаю, ты смущен моей рекомендацией. Я согласен со всем, что ты сказал. Но это ложная дихотомия. Я предлагаю избегать использования min из-за популярности using namespace std (или даже using std::min, с которым, я полагаю, у вас не будет такой большой проблемы). Многие из нас сотрудничают с авторством программного кода с другими, которые не так внимательны, и, чтобы избежать возможности ломать голову, давайте просто полностью избежим проблемы.   -  person Brian Cain    schedule 27.09.2013
comment
@BrianCain - я совсем не смущен.   -  person Pete Becker    schedule 27.09.2013
comment
@PeteBecker, Хорошо, что у вас все хорошо, а у меня хорошо ;)   -  person Brian Cain    schedule 27.09.2013


Ответы (2)


Вы правы в том, что унарный минус, примененный к INT_MIN, может быть неопределенным, но в вашем примере этого не происходит.

-a - min анализируется как (-a) - min. Переменная min участвует только в двоичном вычитании, и только первый операнд должен быть строго отрицательным, чтобы результат был определен.

Если компилятор преобразует вычитание во что-то другое, он обязан убедиться, что новая версия всегда вычисляет то же самое, что и старая версия.

person Pascal Cuoq    schedule 25.09.2013
comment
Так это в основном то же самое, что и min + a? - person user2672807; 26.09.2013
comment
@user2672807 user2672807 Это то же самое, что и -(min + a), когда ни одна из версий не переполняется. Кажется, я не могу найти значения, для которых одно вызывает переполнение, а другое нет, но я не могу сказать, что их нет (пока). - person Pascal Cuoq; 26.09.2013
comment
@PascalCuoq: если предположить, что x является int, и предположить, что дополнение 2: -x переполняется тогда и только тогда, когда x равно INT_MIN. INT_MIN + x переполняется тогда и только тогда, когда x строго отрицательно. Таким образом, -(INT_MIN + x) переполняется тогда и только тогда, когда x строго отрицательно или равно нулю. Между тем - x - min переполняется тогда и только тогда, когда -x переполняется или не является строго отрицательным. То есть тогда и только тогда, когда x равно нулю или отрицательно. Так что вы правы, условия переполнения одинаковы. - person Steve Jessop; 26.09.2013

Результат x - y определяется как математический результат вычитания y из x. Если математический результат может быть представлен в типе результата (в данном случае int), то переполнения не будет.

Компилятор может преобразовать выражение любым способом, например, изменив

x - y

to

x + (-y)

но только если преобразование сохраняет то же поведение в тех случаях, когда исходное поведение четко определено. В случае y == INT_MIN он все еще может выполнять преобразование до тех пор, пока неопределенное поведение оценки -INT_MIN дает тот же конечный результат (что обычно и происходит).

Чтобы ответить на вопрос в заголовке:

Вычитается ли INT_MIN из любого целого числа, которое считается неопределенным поведением?

INT_MIN - INT_MIN == 0 и не может переполняться.

Кстати, я думаю, вы имеете в виду int, а не «целое число». int — это всего лишь один из нескольких целочисленных типов.

person Keith Thompson    schedule 25.09.2013