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

Почему компилятор не предупредил меня о пустом операторе if?

Я использую Keil uVision v4.74 и включил опцию "Все предупреждения".

Я написал следующий преднамеренный код:

if(condition matched)
{
 //do something
}

Когда я перестроил свой проект, я получил 0 ошибок, 0 предупреждений.

Однако, когда я случайно написал:

if(condition matched);
{
 //do something
}

Я также получил 0 ошибок, 0 предупреждений.

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

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

4b9b3361

Ответ 1

Это не ошибка, потому что пустой оператор является действительным оператором; однако, поскольку это, безусловно, подозрительный код, он является идеальным кандидатом для предупреждения компилятора - и на самом деле gcc -Wall -Wextra предупреждает об этом:

int foo(int x) {
  if(x); {
    return 42;
  }
  return 64;
}

 

/tmp/gcc-explorer-compiler116427-37-l1vpg4/example.cpp: In function 'int foo(int)':
2 : warning: suggest braces around empty body in an 'if' statement [-Wempty-body]
if(x); {
^

https://godbolt.org/g/RG1o7t

оба clang и VС++ тоже делают это.

gcc 6 даже более умный (ну, может быть, слишком много), и принимает даже отступы как подсказку, что что-то не так:

/tmp/gcc-explorer-compiler116427-76-1sfy0y/example.cpp: In function 'int foo(int)':
2 : warning: suggest braces around empty body in an 'if' statement [-Wempty-body]
if(x); {
^
2 : warning: this 'if' clause does not guard... [-Wmisleading-indentation]
if(x); {
^~
2 : note: ...this statement, but the latter is misleadingly indented as if it is guarded by the 'if'
if(x); {
^

Итак, либо у вас недостаточно предупреждений, либо ваш компилятор недостаточно умен.

Если у вас нет возможности переключиться на более полезный компилятор, рассмотрите возможность использования инструментов статического анализа; например, в этом случае cppcheck указывает на ошибку (если заданы флаги --enable=all --inconclusive):

[[email protected] ~/scratch]$ cppcheck --enable=all --inconclusive emptyif.c 
Checking emptyif.c...
[emptyif.c:2]: (warning, inconclusive) Suspicious use of ; at the end of 'if' statement.
[emptyif.c:1]: (style) The function 'foo' is never used.

Добавление - соответствующие предупреждения для разных компиляторов (не стесняйтесь обновлять)

соответствующие параметры предупреждения:

  • gcc -Wempty-body; включен в -Wextra;
  • gcc >= 6.0, а также -Wmisleading-indentation может помочь; включен в -Wall;
  • clang -Wempty-body; включен также в -Wextra;
  • Visual С++ C4390, включенный в /W3

Инструменты статического анализа:

  • cppcheck --enable=warning --inconclusive; включен в --enable=all --inconclusive

Ответ 2

Как указано в ответе Matteo, код абсолютно прав. Это интерпретируется следующим образом:

if(condition)
    ;  // do nothing

// unrelated block
{
    // do something
}

Это немного техничность, но условия с пустыми телами имеют очень приятное применение.

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

Или проблемы с безопасностью, переменная tainting, управление буфером, потенциальные проблемы обслуживания, такие как плохие касты и т.д. Существует множество проблем с кодом, которые не попадают в категорию "ошибки компилятора".

Как упоминалось в @jpmc26, этот подход может быть лучше, поскольку вам не нужно переключать компиляторы для его использования. Хотя я также лично нахожу ценность в возможности запускать эти два самостоятельно.