2014-09-21 4 views
29

Таким образом, очевидно, в GCC/C, компилятор компилирует когдаЧто делать, если ((x = 0)) означает в C?

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

используется, в то время, когда

if (x=0){ some code } 

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

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

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

+3

И я не вижу, почему кто-то захочет делать if if ((x = 0)) {...} ', поскольку это условие всегда будет ложным. (Или 'x = N' для любой константы' N'.) Если это в коде, вы столкнулись в дикой природе, возможно, кто-то пытался подавить предупреждение, не понимая, для чего это предупреждение. – fluffy

+3

Кстати, простой трюк, помогающий обнаружить множество случаев, когда = использовался вместо ==, - это всегда ставить константу слева - «if (0 = x)» создаст can't-assign- постоянная ошибка. – keshlam

+3

@keshlam Также известен как [условия Yoda] (https://en.wikipedia.org/wiki/Yoda_conditions). – Palec

ответ

48

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

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

+0

Почему компилятор не предупреждает при вставке в скобки? –

+5

Я подозреваю, что нет хорошего ответа, кроме «потому что они этого не хотели», боюсь. Дополнительный набор круглых скобок теперь настолько вездесущ, что позволяет компилятору подавить предупреждение о том, что он, вероятно, не изменится сейчас. –

+10

@ LưuVĩnhPhúc: Вы прямо заявляете, что знаете, что делаете, а '=' не опечатка. – Jack

19

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

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

В частности, GCC docs сказать о цели из предупреждение:

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

36

Оба являются синтаксически правильными 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... 
} 

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

char *p; 

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

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

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

+0

" от нуля до x и запускать блок если нуль равен нулю "... Что? Должно ли это быть «если нуль истинно»? (Что всегда ложно, BTW) – leonbloy

+0

Спасибо, отредактирован. Первоначально я считал, что блок никогда не будет запущен, но это следствие, а не смысл кода. –

+8

A * Соответствие * Компилятор C не может отклонять либо 'if (x = 0)', либо 'if ((x = 0))'. Он может предупредить обо всем, что ему нравится, включая ту рубашку, которую вы носите. –

Смежные вопросы