Usar continuar en una declaración de cambio


88

Quiero saltar desde el medio de una switchdeclaración a la declaración de bucle en el siguiente código:

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();
}

¿Es esta una forma válida de uso continue? ¿Las continuedeclaraciones ignoran las switchdeclaraciones? ¿C y C ++ difieren en su comportamiento aquí?


Tu idea está bien, pero el ciclo anterior nunca se ejecutará do_something().
antik

5
¿Incluso si el control llega al caso A o al caso B?
Alexander Poluektov

18
Iba a decir, Antik está equivocado en eso. En el caso de A o B, se ejecutará do_something (). De forma predeterminada, saldrá bajo fianza.
Antony Woods

3
@acron, ese es el comportamiento previsto
Matt Joiner

1
Creo que esto parece mucho más sospechoso y confuso y, por lo tanto, más dañino que un goto.
phoeagon

Respuestas:


56

Está bien, la continuedeclaración se relaciona con el bucle adjunto y su código debe ser equivalente a (evitar tales declaraciones de salto):

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

Pero si espera breaksalir del ciclo, como sugiere su comentario (siempre intenta nuevamente con otro algo, hasta que se evalúa como falso), necesitará una estructura diferente.

Por ejemplo:

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

2
"equivalente" sólo en el sentido semántico. el código que genera el compilador es muy diferente. con una declaración de cambio, el compilador puede generar una tabla de salto que evita múltiples comparaciones y, por lo tanto, es mucho más rápido que comparar con cada elemento 1 por 1.
chacham15

@ chacham15, ¿por qué el compilador no puede generar el mismo código para ambos?
Avakar

Las sentencias switch @avakar generan tablas de salto, mientras que la otra representación es una serie de evaluaciones lógicas. tabla de salto de Google para obtener más información.
chacham15

@ chacham15, ¿qué impide que el compilador genere una tabla de salto para las dos declaraciones if o una serie de evaluaciones lógicas para el conmutador?
Avakar

1
Las declaraciones de cambio de @avakar requieren que los casos sean valores constantes, porque ese no es el caso con las declaraciones if, no puede hacer la misma optimización (nota: estoy hablando en el caso general, es posible dados ciertos requisitos (por ejemplo, valores constantes solamente , solo ciertos operadores lógicos, etc.) para realizar la optimización, pero es altamente dependiente del compilador y YMMV).
chacham15

20

Sí, está bien, es como usarlo en una ifdeclaración. Por supuesto, no puede usar a breakpara salir de un bucle desde el interior de un interruptor.


Pero ifno tiene ningún efecto sobre el comportamiento de continueo break. ¿Qué quieres decir con que se parece?
Matt Joiner

@ Matt Quiero decir que continuará el ciclo en ambos casos.

1
@Neil, está bien, confusión evitada.
Matt Joiner

1
@ KiJéy No puedo encontrar ninguna referencia para esto, y en muchos años de programación en C nunca he visto ningún compilador que admita esto ... ¿Dónde diablos encontraste esto?
arjunyg

2
Lo siento, vi esto en PHP, pensé que era una práctica antigua, resulta que es solo PHP ...
Ki Jéy

15

Sí, continue será ignorado por la instrucción switch y pasará a la condición del bucle que se probará. Me gustaría compartir este extracto de la referencia del lenguaje de programación C de Ritchie:

La continuedeclaración está relacionada con break, pero se usa con menos frecuencia; que hace que la próxima iteración del for, whileo dode bucle para empezar. En whiley do, esto significa que la parte de prueba se ejecuta inmediatamente; en el for, el control pasa al paso de incremento.

La instrucción continue se aplica solo a bucles, no a una switchinstrucción. Un continuedentro de un switchinterior de un bucle provoca la siguiente iteración del bucle.

No estoy seguro de eso para C ++.


8

Es sintácticamente correcto y estilísticamente correcto.

Un buen estilo requiere que cada case:declaración debe terminar con una de las siguientes:

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

Además, siguiendo case (x):inmediatamente con

 case (y):
 default:

está permitido: agrupar varios casos que tienen exactamente el mismo efecto.

Todo lo demás se sospecha que es un error, al igual que if(a=4){...} Por supuesto que es necesario encerrar bucle ( while, for, do...while) para continueel trabajo. No volverá a estar case()solo. Pero una construcción como:

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

...está bien.


2
perdón por la necropublicación, pero agregaría que una llamada a exittambién sería algo bueno para terminar un caso de interruptor.
Vality

1
Bueno, voy a obtener todo el Dr. Frankenstein aquí y también default:
señalaré

1
@SlySven: Léxicamente, no es así, pero si no tiene una buena razón para no hacerlo durar, hágalo durar. A menudo es confuso si se usa en otros lugares.
SF.

1
@SF. Bueno, puedo imaginar fácilmente los casos en los que tendría más sentido hacer que el default:caso sea el primero en lugar del último. Como "haz esto, a menos que obtengas los siguientes valores inusuales, que deben manejarse de la siguiente manera".
Ruslan

5

Si bien son técnicamente válidos, todos estos saltos oscurecen el flujo de control, especialmente la continuedeclaración.

Usaría ese truco como último recurso, no como primer recurso.

Qué tal si

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

Es más corto y realiza su trabajo de una manera más clara.


1
perdón por la confusión Alexander, el código es solo para demostración, tengo una buena razón (creo) para la estructura real en mi código.
Matt Joiner

2
@Matt: Eso probablemente significaría una estructura aún más ofuscada ... :)
visitante

-2

Esto puede ser un megabit demasiado tarde, pero puede usarlo continue 2.

Algunas compilaciones / configuraciones de php mostrarán esta advertencia:

Advertencia de PHP: el interruptor de orientación "continuar" es equivalente a "romper". ¿Quiso usar "continue 2"?

Por ejemplo:

$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";
}

Esto dará como resultado:

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

Probado con PHP 5.5 y superior.


3
Esta NO es una pregunta de PHP.
Geoffrey

-4

El interruptor no se considera un bucle, por lo que no puede usar Continuar dentro de una declaración de caso en el interruptor ...


3
La switchdeclaración está dentro de un whilebucle, por lo que continuees perfectamente válida.
Rick
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.