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

Вы должны обновить конфигурационный файл php.ini на сервере своего хост-провайдера, поверьте мне, что, скорее всего, нет ничего плохого в вашем коде. Мне потребовалось почти полтора месяца, чтобы понять, что большинство хостинговых серверов не обновляются в файлах php.ini, например. php 5.5 или более поздней версии.

29
задан Bakuriu 22 September 2014 в 07:58
поделиться

3 ответа

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

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

48
ответ дан David Given 22 September 2014 в 07:58
поделиться

Оба синтаксически верны C, и компилятор должен справиться с этим. Но компилятор может, в зависимости от конфигурации, выдавать предупреждение или даже ошибку (например, - ошибка в 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 и производных языках. Обратите внимание, что речь идет не только о подозрительных компиляторах, но и о людях, читающих код и просматривающих потенциальную ошибку.

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

36
ответ дан Pavel Šimerda 22 September 2014 в 07:58
поделиться

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

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

В частности, Документы GCC говорят это о целях предупреждения:

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

19
ответ дан BartoszKP 22 September 2014 в 07:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: