#include <stdio.h>
void main()
{
int x = 0;
if (x = 0)
printf("It's zero\n");
else
printf("It's not zero\n");
}
Почему оператор if (x = 0) не является ошибкой? Можем ли мы присвоить такое значение в выражении if? Почему он не генерирует ошибку и почему выполняется оператор else?
Это разрешено, но следует добавить дополнительный набор скобок, чтобы указать, что вы действительно хотели проверить результат задания.
Да, вы можете назначать в условии, и это очень полезно, когда вам это нужно, и это вечная ловушка для новых программистов на C. Результат присваивания 0 сравнивается, чтобы убедиться, что он не равен 0; он равен 0, поэтому if ложно и else выполняется. Основная ошибка C. И утверждение эквивалентно: if ((x = 0) != 0) — лишние скобки объясняют компилятору, что вы это подразумеваете. С постоянным нулем это неразумно; с переменной, которая может быть равна нулю, это имеет смысл, и я предпочитаю явное != 0 как часть выражения. if ((x = 0)) глупо выглядит!
Языки программирования, ориентированные на выражения, позволяют писать более лаконичный код. Они не заставляют вас делать отделить команды от запросов.





Да, это вполне допустимый синтаксис, нет причин его запрещать.
Цитирую C11,
[...] An assignment expression has the value of the left operand after the assignment. [...]
Таким образом, значение, хранящееся в операнде LHS, будет использоваться для оценки условия оператора if.
В вашем случае переменная x содержит значение 0 после присваивания, а if (0) равно ЛОЖЬ, поэтому выполняется блок else.
Однако в большинстве случаев вместо сравнения используется синтаксис ошибочно. Вот почему большинство компиляторов выдают предупреждающее сообщение об этой конструкции.
warning: suggest parentheses around assignment used as truth value [-Wparentheses]
if (x = 0) ^
Если вы уверены, что делаете, вы можете обернуть условие if выражением присваивания в дополнительную пару скобок, и все будет хорошо.
Да, разрешено присваивать значение внутри оператора if. Это очень удобно, среди прочего, когда вы хотите вызвать функцию и проверить ее возврат на наличие ошибки:
int rc;
if ((rc = check())) {
// here rc is non-zero, often an indication of a failure
}
Обратите внимание, что я поставил дополнительную пару скобок вокруг своего присваивания — поскольку это такой вездесущий источник путаницы, компиляторы обычно предупреждают о присваивании в блоке if, предполагая, что вы могли сделать опечатку. Дополнительная пара скобок дает понять компилятору, что я именно это и имел в виду.
Кстати, здесь не создано специальное исключение, правильность этого синтаксиса проистекает из общей грамматики C - оператор присваивания оценивает присвоенное значение.
Лично мне такое заикание с двойной скобкой не нравится. Пишу if ((rc = check()) != 0). Это означает то же самое, но более явно.
@JonathanLeffler, конечно, я считаю, что это вопрос личных предпочтений.
int rc = check(); if ( rc != 0 )... является МНОГО менее подверженным ошибкам, а также позволяет выполнять гораздо более сложную проверку ошибок.
@AndrewHenle Я не считаю эту конструкцию особенно подверженной ошибкам. Это становится еще более интересным, если вы хотите вызывать эту функцию выборочно, основываясь на результате какого-либо другого условия (используя функцию короткого замыкания). В любом случае, YMMV и никто не заставляет вас его использовать.
@GovindParmar Я парень на С++, для меня оператор - это функция ))) Я думаю, что в C лучше оценивать.
@SergeyA На чем ТАК ты набрал 43к+ очков репутации?!!? ;-) Вероятно, не проходит и дня без четырех или пяти вопросов о проблемах, вызванных ошибками присваивания в операторе if. Что я вижу.
@AndrewHenle вряд ли аргумент. Люди также склонны возвращать указатели на локальные переменные из функций и передавать указатели по значению (и ожидать, что это изменит значение переданной переменной) - это причина для запрета локальных переменных или передачи по значению? C — сложный инструмент, и его нужно изучать. В любом случае, у вас есть свое мнение, у меня свое.
@SergeyA едва ли аргумент Верно. Но опять же, «Посмотрите на все капли дождя» тоже не аргумент. Это будет свидетельство, поддерживающий аргумент «Идет дождь». В данном случае это присваивание в операторе if, которое приводит к ошибкам. Ссылка на другой источник ошибок не является опровержением.
В C единственным требованием для оператора if является то, что он должен содержать выражение. Истинность утверждения основана на том, равно нулю ли выражение.
Оператор присваивания также оценивает присвоенное значение, поэтому if (a = 0) будет ложным, тогда как if (a = x), где x != 0 будет истинным.
Поскольку оператор присваивания является выражением, его можно поместить в оператор if, хотя частой ошибкой новичков является использование оператора присваивания там, где они намеревались использовать оператор проверки на равенство ==.
Один из способов избежать этого — ошибка: если какая-либо из сторон сравнения представляет собой r-значение, поместите его слева, так что если вы когда-нибудь случайно используете = там, где вы имели в виду ==, вы получите ошибку компиляции. Сравнивать:
if (p = NULL) // Valid syntax
...
if (NULL = p) // Syntax error
...
Вы должны получить предупреждение от вашего компилятора, и если вы этого не сделаете, включите уровень предупреждения.