Использование continue в операторе switch

88

Я хочу перейти от середины switchоператора к оператору цикла в следующем коде:

while (something = get_something())
{
    switch (something)
    {
    case A:
    case B:
        break;
    default:
        // get another something and try again
        continue;
    }
    // do something for a handled something
    do_something();
}

Это действительный способ использования continue? Являются ли continueзаявления игнорировались switchзаявления? Отличаются ли здесь C и C ++ своим поведением?

Мэтт Джойнер
источник
Ваша идея хороша, но приведенный выше цикл никогда не будет выполнен do_something().
antik
5
Даже если контроль достигает случая A или случая B?
Александр Полуэктов
18
Я собирался сказать, что Antik ошибается в этом. В случае A или B будет выполняться do_something (). По умолчанию это будет залог.
Энтони Вудс
3
@acron, это предполагаемое поведение
Мэтт Джойнер
1
Я думаю, что это выглядит гораздо более подозрительно и запутанно и, следовательно, более вредно, чем файл goto.
phoeagon

Ответы:

56

Это нормально, этот continueоператор относится к закрывающему циклу, и ваш код должен быть эквивалентен (избегая таких операторов перехода):

while (something = get_something()) {
    if (something == A || something == B)
        do_something();
}

Но если вы ожидаете breakвыхода из цикла, как предлагает ваш комментарий (он всегда пытается снова с другим чем-то, пока не будет оценено как ложное), вам понадобится другая структура.

Например:

do {
    something = get_something();
} while (!(something == A || something == B));
do_something();
посетитель
источник
2
«эквивалент» только в семантическом смысле. код, который генерирует компилятор, очень отличается. с помощью оператора switch компилятор может сгенерировать таблицу переходов, которая избегает множественных сравнений и, таким образом, намного быстрее, чем сравнение каждого элемента 1 на 1.
chacham15
@ chacham15, почему компилятор не может сгенерировать один и тот же код для обоих?
avakar
Операторы переключения @avakar создают таблицы переходов, тогда как другое представление представляет собой серию логических вычислений. таблица переходов Google для получения дополнительной информации.
chacham15
@ chacham15, что мешает компилятору генерировать таблицу переходов для двух операторов if или серии логических вычислений для переключателя?
avakar
1
Операторы переключения @avakar требуют, чтобы кейсы были постоянными значениями, потому что это не относится к операторам if, они не могут выполнять ту же оптимизацию (примечание: я говорю в общем случае, это возможно при определенных требованиях (например, только значения const , только определенные логические операторы и т. д.) для оптимизации, но это сильно зависит от компилятора и YMMV).
chacham15
20

Да, это нормально - это все равно что использовать его в ifзаявлении. Конечно, вы не можете использовать a breakдля выхода из цикла внутри переключателя.


источник
Но ifне влияет на поведение continueили break. Как вы имеете в виду, что это похоже
Мэтт Джойнер
@Matt Я имею в виду, что он продолжит цикл в обоих случаях.
1
@ Нил, хорошо, путаница предотвращена.
Мэтт Джойнер
1
@ KiJéy Я не могу найти никакого справочника по этому поводу, и за многие годы программирования на C я никогда не видел компилятора, который бы это поддерживал ... Где ты это нашел?
arjunyg
2
Вау, извините, я видел это в PHP, подумал, что это старая практика, но оказалось, что это просто PHP ...
Ки Джеи
15

Да, continue будет проигнорирован оператором switch и перейдет в условие цикла, которое нужно проверить. Я хотел бы поделиться этим отрывком из справочника по языку программирования C от Ричи:

continueЗаявление связано break, но используется реже; это приводит к выполнению следующей итерации вмещающего for, whileили doпетли , чтобы начать. В whileи doэто означает, что тестовая часть выполняется немедленно; в for, управление переходит к шагу приращения.

Оператор continue применяется только к циклам, но не к switchоператору. A continueвнутри switchвнутри цикла вызывает следующую итерацию цикла.

Я не уверен насчет C ++.

Ислам Эльшахат
источник
8

Это синтаксически правильно и стилистически приемлемо.

Хороший стиль требует, чтобы каждое case:утверждение заканчивалось одним из следующих слов:

 break;
 continue;
 return (x);
 exit (x);
 throw (x);
 //fallthrough

Кроме того, case (x):сразу после

 case (y):
 default:

допустимо - объединение нескольких случаев, которые имеют точно такой же эффект.

Что - нибудь еще есть подозрение, что ошибка, так же , как if(a=4){...} Вы , конечно , нужны ограждающий цикл ( while, for, do...while) для continueк работе. Он не вернется к case()одиночеству. Но такая конструкция, как:

while(record = getNewRecord())
{
    switch(record.type)
    {
        case RECORD_TYPE_...;
            ...
        break;
        default: //unknown type
            continue; //skip processing this record altogether.
    }
    //...more processing...
}

...хорошо.

SF.
источник
2
извините за некропостинг, но я бы добавил, что вызов к exitтакже обычно был бы хорошей вещью для завершения случая переключения.
Vality
1
Что ж, я собираюсь собрать здесь всего доктора Франкенштейна и также указать, что default:это не обязательно должна быть последняя / нижняя запись - как указывает этот вопрос ...
SlySven
1
@SlySven: С лексической точки зрения это не так, но если у вас нет веской причины не делать это последним, сделайте это последним. Это часто сбивает с толку, если используется в других местах.
SF.
1
@SF. Что ж, я легко могу представить себе случаи, когда было бы разумнее делать default:прецедент первым, а не последним. Например, «сделайте это, если не получите следующие необычные значения, с которыми следует обращаться следующим образом».
Руслан
5

Хотя с технической точки зрения все эти скачки затрудняют понимание потока управления - особенно continueутверждения.

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

Как насчет

while (something = get_something())
{
    switch (something)
    {
    case A:
    case B:
        do_something();
    }        
}

Он короче и работает более четко.

Александр Полуэктов
источник
1
извините за путаницу, Александр, код предназначен только для демонстрации, у меня есть веская причина (я считаю) для фактической структуры в моем коде.
Мэтт Джойнер
2
@Matt: Это, вероятно, означало бы еще более запутанную структуру ... :)
посетитель
-2

Это может быть мегабит слишком поздно, но вы можете использовать continue 2.

Некоторые сборки / конфигурации php выводят это предупреждение:

Предупреждение PHP: переключатель таргетинга «continue» эквивалентен «break». Вы хотели использовать "продолжить 2"?

Например:

$i = 1;

while ($i <= 10) {
    $mod = $i % 4;
    echo "\r\n out $i";
    $i++;
    switch($mod)
    {
        case 0:
            break;
        case 2:
            continue;
            break;
        default:
            continue 2;
            break;
    }
    echo " is even";
}

Это выведет:

out 1
out 2 is even
out 3
out 4 is even
out 5
out 6 is even
out 7
out 8 is even
out 9
out 10 is even

Протестировано с PHP 5.5 и выше.

Адриан С
источник
3
Это НЕ вопрос PHP.
Джеффри
-4

Switch не считается циклом, поэтому вы не можете использовать Continue внутри оператора case в switch ...

Джитендра Нагар
источник
3
switchОператор находится внутри whileцикла, так что continueвполне допустимо.
Rick