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

Что делать, если ((x = 0)) означает в C?

Таким образом, очевидно, что в gcc/C компилятор компилируется, когда

if ((x=0)){ some code }

тогда как

if (x=0){ some code }

то компилятор отказывается компилировать.

В чем разница между двумя?

В качестве примечания, я знаю, в чем разница между x==0 и x=0. Я просто изучаю, как C ведет себя, когда встречается с некоторыми странными кодами.

4b9b3361

Ответ 1

Нет никакой разницы, по коду.

Все, что происходит, заключается в том, что высказывание x=0 вместо x==0 является такой распространенной ошибкой, что большинство компиляторов будут выдавать предупреждение (или ошибку в вашем случае), когда они его видят. Дополнительный набор круглых скобок - это общий трюк, чтобы закрыть компилятор - эквивалент слова "да, я действительно хотел это сделать".

Ответ 2

Оба являются синтаксически правильными C, и компилятор должен справиться с ним. Но компилятор может, в зависимости от конфигурации, выдать предупреждение или даже ошибку (например, -Werror в gcc), потому что один из них настолько подозрительный, что вы никогда не ожидали, что он будет преднамеренным. Когда вы используете что-то вроде if (x = 0) { ... } (назначьте ноль до x и запустите блок, если нуль не равен нулю), вы почти всегда на самом деле означаете if (x == 0) { ... } (запустите блок, если x равно нулю).

Теперь давайте выясним, почему if ((x = 0)) { ... } не считается достаточно подозрительным, чтобы гарантировать тот же тип предупреждения (этот конкретный код по-прежнему является подозрительным, поскольку условие всегда оценивается до нуля, а тело никогда не запускается)...

Там есть идиома, используемая некоторыми разработчиками C (я один из них), где вы помещаете назначение в круглые скобки и используете функцию, которая даже присваивает самому значению, и это назначенное значение.

Пример:

#include <stdio.h>

int main(int argc, char **argv)
{
    int c;

    while ((c = getchar()) != '\n')
            printf("Character: '%c' (0x%02x)\n", c, c);

    return 0;
}

Проверьте пример:

$ ./test
Hello!
Character: 'H' (0x48)
Character: 'e' (0x65)
Character: 'l' (0x6c)
Character: 'l' (0x6c)
Character: 'o' (0x6f)
Character: '!' (0x21)

Важной частью было условие (c = getchar()) != '\n', где вы сначала назначили результат getchar() на c, а затем проверяли его на определенное значение. В этом случае мы читаем символы один за другим со стандартного ввода до строки и (технически, пока не будем читать символ \n). Основным преимуществом этого способа является то, что он позволяет вам вставлять getchar() в тест. В противном случае вам пришлось бы использовать нотацию запятой, бесконечный цикл с разрывом или поставить его как перед циклом, так и в конце цикла.

Иногда вы сравниваете ненулевые значения, такие как \n, -1 и аналогичные, но иногда сравниваете с нолем или, при работе с указателями, на NULL. Давайте найдем пример для NULL, что довольно часто встречается при распределении памяти.

char *p;

if ((p = malloc(50)) == NULL) {
    ...handle error...
}

Конечно, вы могли бы написать его как:

char *p;

p = malloc(50);
if (p == NULL) {
    ...handle error...
}

Но в зависимости от вашего вкуса вы также можете использовать:

char *p;

if (!(p = malloc(50))) {
    ...handle error...
}

Или даже поверните его в обратном направлении (что, кстати, противоречит моему предпочтению всегда обрабатывать случай ошибки):

char *p;

if ((p = malloc(50))) {
    ...do stuff...
} else {
    ...handle error...
}

В последнем случае условие (p = malloc(50)), которое в точности эквивалентно p = malloc(50), но последнее очень подозрительно из-за уже упомянутой распространенной ошибки выполнения задания вместо сравнения на C и производных языках. Обратите внимание, что это касается не только подозрительных компиляторов, но и людей, читающих код и рассматривающих потенциальную ошибку.

Резервные круглые скобки - это просто средство рассказать читателям и компилятору, что это назначение определенно преднамеренное и что это не является причиной этой общей ошибки.

Ответ 3

Код не должен "отказываться" от компиляции, если у вас нет -Werror. Если у вас есть предупреждения, это может сказать вам:

предупреждение: предлагать круглые скобки вокруг присваивания, используемые как значение истины [-Wparentheses]          while (*dest++ = *src++)

В частности, GCC docs сообщают об этой цели:

Предупреждать, если круглые скобки опущены в определенных контекстах, например, когда есть назначение в контексте, где ожидается истинное значение, или когда операторы вложены, чей приоритет часто получают люди смущен.