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

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

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

if(condition matched)
{
 //do something
}

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

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

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

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

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

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

 Dmiters27 мая 2016 г., 19:04
@ Vector9 Согласен, не могу придумать ни одной законной причины объявитьif заявление без тела. Похоже, он должен предупреждать по умолчанию, не требуя от компилятора дополнительных предупреждений.
 Ian Ringrose27 мая 2016 г., 20:22
@MatteoItalia, тогда не используйте C или C ++! Модуль 2 будет намного лучшим вариантом, если вы заботитесь о безопасности.
 Matteo Italia27 мая 2016 г., 20:20
@IanRingrose: напротив, учитывая, что среда выполнения совершенно не имеет систем безопасности по соображениям производительности, крайне желательно иметь весь возможный статический анализ во время компиляции.
 Hot Licks27 мая 2016 г., 22:23
Имейте в виду, что многие наборы макросов создают подобную ситуацию справа и слева, поскольку биты кода «закомментированы» или не основаны на глобальных настройках макропеременных.
 Akshay Immanuel D27 мая 2016 г., 14:19
я пометил его как keil, потому что ожидал, что кто-то из keil сможет сказать почему или подумать об этом, чтобы улучшить свою IDE. Я не хочу, чтобы кто-то использовал Кейла, чтобы пройти через ту же проблему, что и я. GCC выдает предупреждение, как сказал @Matteo
 Hot Licks27 мая 2016 г., 23:49
@ jpmc26 - подумай, буду ли яif (a) some_dump_macro;, Если глобальный флаг где-то выключаетсяsome_dump_macro тогда я в конечном итогеif (a);.
 ckruczek27 мая 2016 г., 13:59
Почему он должен? Это прекрасно сформированное и юридическое заявление. Здесь нет ничего предупреждающего.
 GrandOpener27 мая 2016 г., 20:58
@ckruczek Но ... это именно то, для чего нужны предупреждения. Если бы это не было правильно сформировано и законно, это было бы ошибкой. Предупреждения относятся к вещам, которые являются законными, но подозрительными как вероятные логические ошибки.
 Akshay Immanuel D27 мая 2016 г., 14:00
Когда я объявляю переменную и не использую ее, он говорит: «переменная объявлена, но не определена». Должен ли он сказать что-то вроде «если используется выражение, но нет тела для утверждения if?»
 Ian Ringrose27 мая 2016 г., 16:08
Компилятор должен вывести одно и только одно предупреждение: «Вы используете c, не ожидайте сети безопасности».
 jpmc2627 мая 2016 г., 23:17
@HotLicks Это звучит интересно для меня, потому что я не могу вспомнить случай, когда это не принесло бы столько же 1) "закомментировать"if также блокировать или 2) инвертировать условное выражение и сделать утверждение, которое «закомментировано»,else блок или что-то подобное. Так что, похоже, этой ситуации можно избежать, но я не эксперт по Си, возможно, есть вещи, о которых я не думаю.
 M.M28 мая 2016 г., 14:55
потому что компилятор keil не очень удобен для пользователя
 someone27 мая 2016 г., 14:17
Здесь я хочу упомянуть одну вещь. Это совсем не связано сkeil.. в общем программировании также это произойдет.

Ответы на вопрос(2)

код абсолютно действителен. Это интерпретируется так:

if(condition)
    ;  // do nothing

// unrelated block
{
    // do something
}

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

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

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

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

Решение Вопроса

Это не ошибка, потому что пустое утверждениеявляется действительное утверждение; однако, поскольку это, безусловно, подозрительный код, он является идеальным кандидатом для предупреждения компилятора - и на самом деле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 и VC ++ делают это тоже.

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.
Приложение - соответствующие предупреждения для различных компиляторов (не стесняйтесь обновлять)

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

НКУ -Wempty-body; включен в-Wextra;НКУ> = 6.0, также-Wmisleading-indentation может помочь; включен в-Wall;лязг -Wempty-body; включен в-Wextra тоже;Visual C ++ C4390, включен в/W3

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

cppcheck --enable=warning --inconclusive; включен в--enable=all --inconclusive
 Matteo Italia27 мая 2016 г., 14:13
@ Vector9: я не знаю, я никогда не использовал Keil. Кроме того, кажется, что сам Keil в основном является IDE, какой бэкэнд компилятора он использует? К сожалению, «второстепенные» компиляторы для встраиваемых платформ часто отстают от «основных» компиляторов в этом виде диагностики.
 jpmc2627 мая 2016 г., 23:10
@davenpcj Предложение использования linter может стоить опубликовать в качестве ответа, поскольку (по-видимому) не потребует переключения компиляторов.
 Akshay Immanuel D27 мая 2016 г., 14:22
Мой кейл использует Armcc.exe v5.03.0.76
 mucaho27 мая 2016 г., 17:30
Есть ли аналоговый флаг дляclang что даст это предупреждение?
 davenpcj27 мая 2016 г., 20:04
Lint также предупредит о неожиданном изменении отступа.
 Matteo Italia27 мая 2016 г., 17:38
@mucaho:-Wextra включает его даже в лязг; конкретный флаг для этого предупреждения такой же, как и дляgccт.е.-Wempty-body.
 Matteo Italia27 мая 2016 г., 14:28
@ Vector9: краткий обзор списка предупреждений, поддерживаемых armcc, похоже, не связан с этой проблемой. Тем не менее, я вижу, что Кейлподдерживает с помощьюgccТаким образом, вы можете попробовать (возможно, не в производстве, а просто время от времени, чтобы взглянуть на другой набор диагностики компилятора). Но, опять же, я не эксперт по Keil / armgcc, поэтому я не знаю, можно ли использовать его в основном в качестве замены для замены или это будет кошмаром для переключения между компиляторами.
 Akshay Immanuel D27 мая 2016 г., 14:12
Насколько больше вы можете провернуть Кейла за пределами всех предупреждений?
 Cody Gray27 мая 2016 г., 16:34
Да, MSVC предупреждает:warning C4390: ';': empty controlled statement found; is this the intent?, Это на самом делепредупреждение уровня 3, так что вам даже не нужно / W4. Уровень предупреждения по умолчанию поймает этот.

Ваш ответ на вопрос