Существуют ли какие-либо исключения при удалении фигурных скобок для оператора if?

Я студент информатики, и некоторое время назад наш профессор объяснил нам, что в языке C мы можем удалить фигурные скобки, когда есть только одно выражение, например:

if (a)
  do b

но мы не можем сделать что-то вроде этого:

if(a)
  do b
  do c

потому что это будет делать более одного оператора.

Но он также сказал нам, что есть исключение об удалении фигурных скобок, чего мы не можем сделать, даже если это только одно выражение. Я много искал, но единственное, что я нашел, это то, что я не могу сделать это в цикле do-while, но мы говорим об операторах if, какая-нибудь помощь?

Редактировать: мы также говорили о вложенных операторах if, может быть, это об этом?


person WhiteNoise    schedule 13.11.2018    source источник
comment
Никогда не слышал и не сталкивался с ситуацией, когда {} требовалось для оператора if.   -  person Fiddling Bits    schedule 13.11.2018
comment
Я почти уверен, что вы также можете удалить фигурные скобки цикла do-while.   -  person Quentin    schedule 13.11.2018
comment
Возможно, исключение вашего профессора скорее стилистическое, чем синтаксическое.   -  person Ian Abbott    schedule 13.11.2018
comment
en.wikipedia.org/wiki/Dangling_else#C   -  person    schedule 13.11.2018
comment
объявление переменной, например int n = 1;, является отдельным оператором, но если оно помещено в фигурные скобки { int n = 1; }, оно принадлежит другому контексту и недоступно из остального контекста.   -  person Giovanni Cerretani    schedule 13.11.2018


Ответы (4)


Ваш профессор, вероятно, говорит о такой ситуации:

if (a)
    if (b)
        printf("a and b\n");
else  // this goes with the inner "if"
    printf("not a\n");

Вопреки тому, что предполагает отступ, else связан не с внешним оператором if, а с внутренним оператором if. В этом случае вам нужно добавить фигурные скобки к телу внешнего if, чтобы else было правильно связано:

if (a) {
    if (b)
        printf("a and b\n");
}
else
    printf("not a\n");

Лучше всего всегда использовать фигурные скобки для тел условных и циклических конструкций, чтобы предотвратить такого рода двусмысленность и связанные с ними ошибки.

person dbush    schedule 13.11.2018
comment
Это называется висячей else неоднозначностью, и компиляторы построены так, чтобы сопоставлять else с ближайшим if. - person Paul Ogilvie; 13.11.2018
comment
Хорошо, это кажется очень хорошим, и, вероятно, это так; но может быть что-то, что дает ошибку компиляции? Редактировать: я также думал об объявлении переменной в операторе только если, что просто уничтожило бы новую переменную, сделав ее бесполезной. - person WhiteNoise; 13.11.2018
comment
@cmaster Хорошо, спасибо. Я почти уверен, что тогда это болтается еще, поскольку мы также говорили о гнездовых операторах if. - person WhiteNoise; 13.11.2018
comment
@WhiteNoise Кстати: ошибка google goto fail для громкого примера из реального мира ^^ - person cmaster - reinstate monica; 13.11.2018
comment
@WhiteNoise Забудьте о моем комментарии об ошибке компилятора, невозможной с if(). Это не правильно. Подробности см. в ответе Антти Хаапала (stackoverflow.com/a/53284483/2445184). Сейчас я удалю свой неправильный комментарий. - person cmaster - reinstate monica; 14.11.2018

Но он также сказал нам, что есть исключение об удалении фигурных скобок, чего мы не можем сделать, даже если это только одно выражение.

Я считаю, что ваш профессор пытается научить вас лучшим практикам. Несмотря на то, что мы можем писать операторы if без фигурных скобок, насколько это касается языка C, мы никогда не должны этого делать. На самом деле это не субъективное личное предпочтение стиля, а вопрос безопасности программы.

Потому что очень легко написать такие ошибки:

if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
    goto fail;
    goto fail;  /* MISTAKE! THIS LINE SHOULD NOT BE HERE */

2-й goto всегда будет выполняться, что не предполагалось. Осмелюсь заявить, что каждый программист на C, который допускает этот стиль, также написал эту ошибку. Я, конечно, делал это время от времени и сам, прежде чем полностью перестал использовать этот стиль.

Из соображений безопасности известные стандарты кодирования, такие как CERT-C и MISRA-C, запрещают использование if и т. д. без фигурных скобок. См. CERT-C EXP19-C и MISRA-C:2012, правило 15.6.

person Lundin    schedule 13.11.2018

Что ж, всегда можно использовать один оператор без фигурных скобок. Но что, если у вас нет никаких утверждений:

if (ham)
    int eggs = spam();

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

if (ham) {
    int eggs = spam();
}

делает. Есть один составной оператор с объявлением с инициализацией, которая вызывает функцию; и 0 утверждений. Конечно, это не очень полезно, потому что в противном случае переменная не используется...

person Antti Haapala    schedule 13.11.2018
comment
Отлично, вы нашли синтаксическую невозможность :-) - person cmaster - reinstate monica; 14.11.2018
comment
@cmaster, но это не только одно утверждение;) - person Antti Haapala; 14.11.2018
comment
Разве определение переменной не является также одним оператором? Просто не тот тип оператора, который разрешен в качестве тела if()? - person cmaster - reinstate monica; 14.11.2018

Трудно отлаживать, когда вы используете макросы (многострочные) с таким синтаксисом. Вы должны посмотреть на предварительно обработанный код C, чтобы определить проблему.

#define MULTISTATEMENT a=5;\
                       b=5;
#include <stdio.h>

int main() {
   int a = 10, b = 10;
   if(a == 10)
       MULTISTATEMENT
   else
       a = 3;
   printf("a = %d b = %d\n", a, b);
   return 0;
}

Этот код генерирует ошибку. Поместите {} либо вокруг макроса, либо вокруг оператора if, чтобы скомпилировать этот код.

person bhanu7k    schedule 19.11.2018