Рассмотрим следующее switch
утверждение:
switch( value )
{
case 1:
return 1;
default:
value++;
// fall-through
case 2:
return value * 2;
}
Этот код компилируется, но действительно ли он (= определенное поведение) для C90 / C99? Я никогда не видел код, в котором регистр по умолчанию не последний.
РЕДАКТИРОВАТЬ:
Как пишут Джон Кейдж и KillianDS : это действительно уродливый и запутанный код, и я хорошо это знаю. Меня просто интересует общий синтаксис (он определен?) И ожидаемый результат.
c
switch-statement
tanascius
источник
источник
goto
не злой. Культовые последователи груза есть! Вы не могли себе представить, к чему могут пойти люди, избегая крайностей,goto
потому что они, как утверждается, настолько злы, что создают непонятный беспорядок в их коде.goto
основном для имитации что - то вродеfinally
пункта в функциях, где RESSOURCES (файлы, память) должны быть освобождены при остановке, и повторять для каждого случая ошибки спискаfree
иclose
не помогают читаемости. Хотя есть одно использованиеgoto
, которого я хотел бы избежать, но не могу, это когда я хочу выйти из цикла, и я нахожусьswitch
в этом цикле.Ответы:
В стандарте C99 об этом не говорится, но, принимая во внимание все факты, это совершенно справедливо.
А
case
иdefault
метка эквивалентныgoto
метке. См. 6.8.1 Помеченные заявления. Особенно интересен 6.8.1.4, который включает уже упоминавшееся устройство Даффа:Изменить : код внутри переключателя ничего особенного; это нормальный блок кода, как в-
if
состоянии, с дополнительными метками перехода. Это объясняет поведение при падении и почемуbreak
это необходимо.6.8.4.2.7 даже приводит пример:
Константы регистра должны быть уникальными в операторе switch:
Все случаи оцениваются, затем он переходит к метке по умолчанию, если дано:
источник
default
дело, доминирующее над другими делами примерно на 100: 1, и я не знаю, является ли оно действительным или неопределенным, чтобы сделатьdefault
первое дело.Операторы case и инструкция по умолчанию могут встречаться в любом порядке в операторе switch. Предложение по умолчанию является необязательным предложением, которое сопоставляется, если ни одна из констант в операторах case не может быть сопоставлена.
Хороший пример :-
очень полезно, если вы хотите, чтобы ваши кейсы были представлены в логическом порядке в коде (например, не говоря, кейс 1, кейс 3, кейс 2 / по умолчанию) и ваши кейсы очень длинные, поэтому вы не хотите повторять весь кейс код внизу по умолчанию
источник
Это действительно и очень полезно в некоторых случаях.
Рассмотрим следующий код:
Дело в том, что приведенный выше код более читабелен и эффективен, чем каскадный
if
. Вы могли бы поставитьdefault
в конце, но это бессмысленно, так как оно сосредоточит ваше внимание на случаях ошибок, а не на обычных случаях (что здесь имеетdefault
место).На самом деле, это не очень хороший пример,
poll
вы знаете, сколько событий может произойти максимум. Моя реальная точка в том , что там есть случаи с определенным набором входных значений , где есть «исключение» и нормальные случаи. Если лучше поместить исключения или нормальные случаи на первый план, это вопрос выбора.В области программного обеспечения я думаю о другом очень обычном случае: рекурсии с некоторыми терминальными значениями. Если вы можете выразить это с помощью переключателя,
default
будет обычное значение, которое содержит рекурсивный вызов и выделенные элементы (отдельные случаи) значения терминала. Обычно нет необходимости фокусироваться на терминальных значениях.Другая причина в том, что порядок дел может изменить поведение скомпилированного кода, и это имеет значение для производительности. Большинство компиляторов генерируют скомпилированный ассемблерный код в том же порядке, в котором он отображается в коммутаторе. Это сильно отличает первый случай от других: все случаи, кроме первого, будут включать скачок, который опустошит конвейеры процессора. Вы можете понять это как предиктор ветвления, по умолчанию запускающий первый появившийся случай в коммутаторе. Если случай гораздо более распространенный, чем у других, у вас есть очень веские основания для того, чтобы поставить его в качестве первого случая.
Чтение комментариев - это особая причина, по которой оригинальный автор задал этот вопрос после прочтения реорганизации компилятора Branch Branch Loop об оптимизации кода.
Тогда это станет неким арбитражем между читабельностью и производительностью кода. Вероятно, лучше оставить комментарий, чтобы объяснить будущему читателю, почему дело появляется первым.
источник
case
. Что удручает, так это то, что он выглядит так же, как синтаксический сахар, и не нарушает существующий код, если поддерживается.да, это действительно, и при некоторых обстоятельствах это даже полезно. Как правило, если вам это не нужно, не делайте этого.
источник
Там нет определенного порядка в инструкции switch. Вы можете рассматривать случаи как что-то вроде именованного ярлыка, как
goto
ярлык. Вопреки тому, что люди думают здесь, в случае значения 2 метка по умолчанию не используется. Чтобы проиллюстрировать на классическом примере, вот устройство Даффа , которое является потомком детей крайностейswitch/case
в C.источник
Один сценарий, в котором я бы посчитал целесообразным расположить «по умолчанию» где-то, кроме конца оператора case, - это конечный автомат, где недопустимое состояние должно сбрасывать машину и действовать, как если бы это было начальное состояние. Например:
альтернативное расположение, если недопустимое состояние не должно сбрасывать машину, но должно быть легко идентифицировано как недопустимое состояние:
Затем код в другом месте может проверять наличие (widget_state == WIDGET_INVALID_STATE) и предоставлять любое сообщение об ошибке или состояние сброса состояния, которое кажется подходящим. Например, в коде строки состояния может отображаться значок ошибки, а параметр меню «Запуск виджета», который отключен в большинстве неактивных состояний, может быть включен как для WIDGET_INVALID_STATE, так и для WIDGET_IDLE.
источник
Включение в другой пример: это может быть полезно, если «default» - это неожиданный случай, и вы хотите записать ошибку, но также сделать что-то разумное. Пример из моего собственного кода:
источник
Существуют случаи, когда вы конвертируете ENUM в строку или конвертируете строку в enum, если вы пишете / читаете в / из файла.
Иногда вам нужно установить одно из значений по умолчанию, чтобы оно охватывало ошибки, сделанные при ручном редактировании файлов.
источник
default
Условие может быть в любом месте внутри коммутатора , который может существовать оговорка случая. Не обязательно быть последним пунктом. Я видел код, который ставит значение по умолчанию в качестве первого предложения.case 2:
Запускается на выполнение , как правило, даже если положение по умолчанию над ним.В качестве теста я поместил пример кода в функцию, которая вызывается
test(int value){}
и выполняется :Выход:
источник
Это действительно, но довольно противно. Я бы предположил, что, как правило, нельзя допускать сбои, так как это может привести к очень грязному коду спагетти.
Почти наверняка лучше разбить эти случаи на несколько операторов switch или более мелких функций.
[править] @Tristopia: Ваш пример:
было бы яснее относительно его намерения (я думаю), если бы оно было написано так:
[edit2] @Tristopia: Ваш второй пример, вероятно, самый чистый пример хорошего использования для продолжения:
..но лично я бы разделил распознавание комментария на его собственную функцию:
источник
r
является массив назначения,wc
входнойwchar_t
коммутатор (utf8_length) {/ * Примечание: код падает через случаи! * / случай 3: r [2] = 0x80 | (туалет & 0x3f); wc >> = 6; wc | = 0x800; случай 2: r [1] = 0x80 | (туалет & 0x3f); wc >> = 6; wc | = 0xc0; случай 1: r [0] = wc; }for(i=0; s[i]; i++) { switch(s[i]) { case '"': case '\'': case '\\': d[dlen++] = '\\'; /* fall through */ default: d[dlen++] = s[i]; } }