Почему этот код имеет значение true?
int main() {
int a = 1;
int b = 0;
if (a = b || ++a == 2)
printf("T: a=%i, b=%i", a, b);
else
printf("F: a=%i, b=%i", a, b);
return 0;
}
Посмотрим на этот простой фрагмент кода. Результат: T: a = 1, b = 0
Почему? (примечание a=b
использует операнд назначения, а не сравнение)
Я понимаю, что ноль присваивается a, тогда a увеличивается на 1. 1 не равно 2. Поэтому результат должен быть a = 1, b = 0. Но почему это условие оценивается как истинное? Ни один из (a=b)
или (++a == 2)
не верен... Что я пропустил?
Вот еще одна короткая программа, которая печатает F, как ожидалось:
int main() {
int a = 1;
int b = 0;
if (a = b) printf("T"); else printf("F");
return 0;
}
Ответы
Ответ 1
Вы путаете себя с вводящим в заблуждение промежутком.
if (a = b || ++a == 2)
совпадает с:
if (a = (b || ((++a) == 2)))
На самом деле это поведение undefined. Хотя между оценкой b
и оценкой ((++a) == 2)
существует точка последовательности, не существует точки последовательности между подразумеваемым присваиванием на a
, а другая записывается в a
из-за явного назначения =
.
Ответ 2
На самом деле назначение имеет самый низкий приоритет оператора, поэтому ваш оператор if эквивалентен:
if ( a = ( b || ( ++a == 2 ) ) )
Итак, вы назначаете a 1, а также увеличиваете его в одном выражении. Я думаю, что это приводит к поведению undefined, но конечным результатом является то, что a - 1 в вашем компиляторе.
Ответ 3
Если вы используете GCC или другой компилятор с подобными полезными предупреждениями, включение предупреждений даст вам очень большой намек на то, что здесь не так. С помощью gcc -Wall
:
предупреждение: предлагать круглые скобки вокруг присваивания, используемые как значение истины
Чтобы быть точным: компилятор интерпретирует код как if (a = (b || ++a == 2))
, и предупреждение указывает на то, что вы пишете его как if ((a = (b || ++a == 2)))
, чтобы подчеркнуть, что код предназначен, а не опечатка для более распространенного if (a == (b || ++a == 2))
.
Поэтому предупреждение требует немного интерпретации. Чтобы получить желаемый эффект, достаточно совместить достаточно, чтобы добавить круглые скобки вокруг другого присваивания, используемого как значение истины, а именно (a = b)
. Тем не менее предупреждение говорит вам о том, что что-то не соответствует этой конкретной строке кода и что оно заслуживает дальнейшего изучения.