Ответ 1
Это вопрос стиля.
Я бы поставил break
за пределы закрывающей скобки, чтобы сделать его более читаемым.
Когда я использую фигурные скобки вокруг блока кода case
в С++ для локализации переменных, я должен помещать break
внутри или вне блока?
case FOO: // 'break' inside
{
int i;
doStuff();
break;
}
case BAR: // 'break' outside
{
int i;
doStuff();
}
break;
Спасибо.
Это вопрос стиля.
Я бы поставил break
за пределы закрывающей скобки, чтобы сделать его более читаемым.
Вы ставите его, где хотите. Убедитесь, что вы остаетесь последовательными на протяжении всего проекта. (Лично я вынул его наружу.)
Я обычно помещаю break
в фигурные скобки, например:
switch (foo) {
case bar: {
int x = 5;
printf("%d\n", x);
break;
}
case baz: {
// ...
break;
}
}
Однако, поскольку это мое правило, я могу свободно его разбить (не каламбур), когда захочу.
Он должен появиться после.
Например:
switch(value)
{
case 0:
{
// this ...
// that ...
// and the other ...
}
break;
}
Отредактированный текст ниже
В основном это улучшает читаемость и ремонтопригодность.
switch (value)
{
case 0:
// Do this...
// Do that...
break;
case 1:
//and the other...
break;
}
и
switch (value)
{
case 0:
// Do this...
// Do that...
if (ObjectWithinScope.Type == Fault)
break;
case 1:
//and the other...
break;
}
Теперь сравните с
switch (value)
{
case 0:
{
// Do this...
// Do that...
}
break;
case 1:
//and the other...
break;
}
и
switch (value)
{
case 0:
{
// Do this...
// Do that...
if (ObjectWithinScope.Type == Fault)
break;
}
case 1:
{
//and the other...
}
break;
}
Когда вы начинаете сталкиваться с случаями вложенных операторов switch, это может сильно запутать.
Просто указатель.
Теперь некоторые из вас по-прежнему задаются вопросом, что я получаю. Вот. Часть устаревшего кода перестала работать, и никто не мог понять, почему. Все это сводилось к фрагменту кода, структурированному следующим образом:
switch (value)
{
case 0:
{
// Do this...
// Do that...
if (ObjectWithinScope.Type == Fault)
break;
}
case 1:
{
//and the other...
}
break;
}
Потребовалось много времени, чтобы привязать этот код, но при проверке журналов изменений он был первоначально следующим:
switch (value)
{
case 0:
{
// Do this...
// Do that...
if (ObjectWithinScope.Type == Fault)
// *** A line of code was here ***
break;
}
case 1:
{
//and the other...
}
break;
}
По общему признанию, исходный код не был согласован с самим собой, но благодаря разрыву в фигурных скобках код скомпилировался, когда одна строка кода была удалена случайно. Если разрыв был за пределами скобок, то этого не было бы.
Все согласны с тем, что мы хотим четко распознаваемого различия между механизмом switch/case...
и действительными действиями, выполняемыми в каждом случае.
Поэтому, если в каждом случае практически ничего не происходит (простое назначение или так), я предлагаю использовать switch
как простой диспетчер и делегировать "реальные" вещи вспомогательным функциям. Это автоматически решает проблему локальных переменных case и вообще скрывает необходимость в фигурных скобках.
switch( operation ) {
case cnegation: r = -value; break;
case cinversion: r = 1./r; break;
case cfaculty: {
double r = value;
while( value != 1 )
r *= --value;
}
break;
}
Должно получиться
switch( operation ) {
case cnegation : r = negate (value) ; break;
case cinversion: r = invert (value) ; break;
case cfaculty : r = faculty(value) ; break;
}
Это действительно зависит от логики вашего кода и того, как он использует фигурные скобки, но для правильного ответа, если вы положили его внутрь, попробуйте поместить все из них внутри.
По моему мнению, вы должны избегать локальных переменных и блоков в операторах switch. Также вам следует избегать длинных, сложных или даже каскадных операторов switch. Но никакого правила без исключения... Я предпочитаю писать оператор break после блока.
Это не имеет большого значения, если вы и ваша команда последовательно выполняете одно и то же. Даже тогда, это не большая проблема, если разные члены команды делают это по-другому.
Я лично предпочитаю после. Причиной является то, что он дает некоторое разделение между машиной оператора switch (прыгающей, исполняющей вещи и выходом) и кодом в фигурных скобках, который исключительно связан с "выполнением" дела.
например:
switch( value )
{
case 0:
{
// code here
}
break;
default:
{
assert(!"unhandled value in switch");
}
break;
}
Я использую только {} для случая, если ему нужны локальные переменные, но если я использую {} для любого случая, я помещаю их во всех случаях.
Я обычно всегда определяю случай по умолчанию для утверждения, если есть какое-либо неожиданное значение. Удивительно, как часто один из этих утверждений стреляет, чтобы напомнить вам о недостающем случае.
Мне не нравится вставлять какие-либо скобки в оператор switch. Лично, если это сложная операция, мне нравится включать ее в функцию. Там нет ничего более раздражающего, чем просмотр инструкции switch, где между каждым "случаем" присутствуют сотни строк кода, а кроме того, некоторые из них повторяются в разных случаях, что делает техническое обслуживание невозможным.
Например:
switch(blah)
{
case 1:
// do one thing
break;
case 2:
doManyThings();
break;
default:
// something
break;
}
Это вопрос стиля, но я положил его после того, как понял определение:
switch (variable)
{
case expression:
statement;
break;
default:
statement;
break;
}
где инструкция представляет собой либо одну команду, либо блок. Разрыв разделен на этот оператор или блок. И да, я добавляю перерыв после дефолта, хотя он лишний. Я также ВСЕГДА кладет фигурные скобки вокруг инструкции. Слишком много раз я добавил еще одно выражение только для того, чтобы разорвать область. И я добавляю разрыв к умолчанию, поскольку я изменил значение по умолчанию: к выражению case: и добавил что-то после него. Оборонительное кодирование - ваш друг.
Однако я могу найти документацию для фактического определения через Microsoft как:
selection-statement:
switch ( expression ) statement
labeled-statement:
case constant-expression : statement
default : statement
Которое указывает, что оно должно быть внутри.
Тем не менее, я думаю, что внешний вид более ясен с точки зрения читателей, но он, безусловно, субъективен.
Поскольку стандарт не ограничивает вас выбором позиции для оператора break
, вы можете выбрать все, что захотите. Лично я использую следующий стиль:
switch ( some_var ) {
case 1: {
// lot of code here
} break;
case 2: /* one call */ break;
case 3: /* one call */ break;
case 4: {
// lot of code here again
} break;
}
Можно многое сказать по стилю использования только одного утверждения для каждого случая и никогда не использовать фигурные скобки. Например:
switch( cond ) { default: foo(); break; case 0: bar(); break; case 1: baz(); break; }
Используя этот стиль, ваш вопрос спорный.
Реальный ответ: Компилятор не заботится. Это вопрос предпочтения.
Я помещаю их внутрь, например руководство по стилю google.
Если использовать фигурные скобки, мне нравится, что открывающая скобка находится в том же столбце, что и закрывающая скобка (которая отличается от google).
switch (var) {
case 0:
{
...
break;
}
case 1:
{
...
break;
}
default:
assert(false);
}
Моя просьба... См. ниже приведенный ниже пример.
Отступывать все случаи переключения и иметь закрывающую скобку переключателя под ключевым словом switch
, точно так же, как в инструкции if
. При необходимости одно и то же правило для каждого оператора case
: открывайте скобки после полуколона, следующих за оператором case
, и закрывайте их под ключевым словом case
, затем отступайте содержимое каждого из операторов case
, включая ключевое слово break
.
Сохраняйте его согласованным (места для отступов и скобок) и короткими (не более 5-10 строк кода в выражении case
. Сложные проекты потерпели неудачу из-за сильно отступов switch
с слишком большим количеством кода в них.
switch (number) {
case 1:
logFileStderr(VERBOSE, "MESSAGE: switch without brackets...\n");
break;
case 2: {
logFileStderr(VERBOSE, "MESSAGE: switch with brackets...\n");
break;
}
default:
logFileStderr(VERBOSE, "WARNING: Unknown option...\n");
break;
}