Використання continue у операторі switch


89

Я хочу перейти від середини 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
Я збирався сказати, антик помиляється в цьому. У випадку A або B, виконується do_something (). За замовчуванням це буде заставою.
Ентоні Вудс,

3
@acron, це передбачувана поведінка
Matt Joiner

1
Я думаю, що це виглядає набагато підозрілішим і заплутанішим і, отже, більш шкідливим, ніж a goto.
phoeagon

Відповіді:


56

Це нормально, continueоператор відноситься до цикла, що включає, і ваш код повинен бути еквівалентним (уникаючи таких операторів стрибка):

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

Але якщо ви очікуєте breakвийти з циклу, як пропонується у вашому коментарі (він завжди намагається повторити щось інше, поки не оцінить як false), вам знадобиться інша структура.

Наприклад:

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

2
"еквівалент" лише у семантичному значенні. код, який створює компілятор, дуже різний. за допомогою оператора switch компілятор може генерувати таблицю переходів, яка дозволяє уникнути множинних порівнянь і, отже, набагато швидше порівняння з кожним елементом 1 на 1.
chacham15,

@ chacham15, чому компілятор не міг згенерувати однаковий код для обох?
avakar

Інструкції перемикача @avakar генерують таблиці переходів, тоді як інше подання являє собою серію логічних оцінок. таблиця переходів google для отримання додаткової інформації.
chacham15

@ chacham15, що заважає компілятору генерувати таблицю переходів для двох операторів if або серії логічних оцінок для комутатора?
авакар

1
У операторах перемикача @avakar потрібно, щоб випадки були постійними значеннями, оскільки це не так у випадку з операторами if, він не може здійснити однакову оптимізацію (примітка: я кажу в загальному випадку, це можливо з урахуванням певних вимог (наприклад, лише значення const , лише деякі логічні оператори тощо) для оптимізації, але це сильно залежить від компілятора та YMMV).
chacham15

20

Так, це нормально - це просто як використання у ifзаяві. Звичайно, ви не можете використовувати a, breakщоб вирватися з циклу зсередини комутатора.


Але ifне впливає на поведінку continueабо break. Як це означає, що це схоже?
Matt Joiner

@Matt Я маю на увазі, що це продовжить цикл в обох випадках.

1
@ Ніл, гаразд, плутанини уникнуто.
Matt Joiner

1
@ KiJéy Я не можу знайти жодних посилань на це, і за багато років програмування на С я ніколи не бачив жодного компілятора, який би це підтримував ... Де ви це знайшли?
arjunyg

2
Вау, вибачте, я бачив це в PHP, думав, що це стара практика, виявляється, це просто PHP ...
Кі Джей

15

Так, продовження буде проігноровано оператором перемикання та перейде до стану тестованого циклу. Я хотів би поділитися цим витягом із посилання на Мову програмування С від Річі:

continueЗаява пов'язана break, але використовується рідше; це призводить до виконання наступної ітерації вміщає for, whileабо doпетлі , щоб почати. У whileі do, це означає, що тестова частина виконується негайно; в for, керування переходить до кроку приросту.

Оператор continue застосовується лише до циклів, а не до switchоператора. 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...
}

... це нормально.


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
вибачте за плутанину Олександре, код призначений лише для демонстрації, у мене є поважна причина (я вважаю) для фактичної структури мого коду.
Matt Joiner

2
@Matt: Це, мабуть, означало б ще більш затуманену структуру ... :)
відвідувач

-2

Це може бути мегабіт до запізнення, але ви можете використовувати continue 2 .

Деякі збірки / конфігури php видадуть таке попередження:

Попередження PHP: перемикач націлювання "продовжити" еквівалентно "перерві". Ви мали на увазі використовувати "продовжити 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є цілком дійсним.
Рік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.