Tengo una situación en la que me gustaría que dos casos en una instrucción de cambio de C ++ cayeran en un tercer caso. Específicamente, el segundo caso pasaría al tercer caso, y el primer caso también pasaría al tercer caso sin pasar por el segundo caso.
Tuve una idea tonta, la probé y ¡funcionó! Envolví el segundo caso en un if (0) {
... }
. Se parece a esto:
#ifdef __cplusplus
# include <cstdio>
#else
# include <stdio.h>
#endif
int main(void) {
for (int i = 0; i < 3; i++) {
printf("%d: ", i);
switch (i) {
case 0:
putchar('a');
// @fallthrough@
if (0) { // fall past all of case 1 (!)
case 1:
putchar('b');
// @fallthrough@
}
case 2:
putchar('c');
break;
}
putchar('\n');
}
return 0;
}
Cuando lo ejecuto, obtengo el resultado deseado:
0: ac
1: bc
2: c
Lo probé tanto en C como en C ++ (ambos con clang) e hizo lo mismo.
Mis preguntas son: ¿Es esto válido C / C ++? ¿Se supone que debe hacer lo que hace?
c++
c
if-statement
switch-statement
language-lawyer
Mark Adler
fuente
fuente
switch(x) { case A: case B: do_this(); if(x == B) also_do_that(); ... }
. Eso también fue, en mi opinión, horrible. Por favor, simplemente escriba cosas como esas como declaraciones, incluso si eso significa que tiene que repetir una línea en dos lugares. Utilice funciones y variables (¡y documentación!) Para reducir el riesgo de actualizaciones posteriores accidentales en un solo lugar.Respuestas:
Sí, esto está permitido y hace lo que quiere. Para una
switch
declaración, el estándar C ++ dice :Entonces, cuando
if
se evalúa la declaración, el flujo de control procede de acuerdo con las reglas de unaif
declaración, independientemente de las etiquetas de los casos que intervengan.fuente
Sí, se supone que esto funciona. Las etiquetas de caso de una instrucción switch en C son casi exactamente como etiquetas goto (con algunas advertencias sobre cómo funcionan con instrucciones switch anidadas). En particular, ellos mismos no definen bloques para las declaraciones que usted considera que están "dentro del caso", y puede usarlos para saltar al medio de un bloque como lo haría con un goto. Al saltar a la mitad de un bloque, se aplican las mismas advertencias que con goto con respecto al salto sobre la inicialización de variables, etc.
Dicho esto, en la práctica probablemente sea más claro escribir esto con una declaración goto, como en:
switch (i) { case 0: putchar('a'); goto case2; case 1: putchar('b'); // @fallthrough@ case2: case 2: putchar('c'); break; }
fuente
bee
(en modo C; en C ++ el error "no se puede saltar de la declaración de cambio a esta etiqueta de caso / salto omite la inicialización de la variable").goto
es la solución más limpia.goto
es muy difamado, pero en realidad no tiene nada de objetable si no está creando estructuras de control complejas manualmente. Todo el "goto considerado dañino" se trataba de escribir código HLL (por ejemplo, C) que se parece a un código emitido por un compilador (salta de un lado a otro por todas partes). Hay muchos buenos usos estructurados de goto como solo hacia adelante (conceptualmente no es diferentebreak
o tempranoreturn
), improbable-reintento-solo-bucle (evita oscurecer la ruta de flujo común y compensa la falta de anidado-continue
), etc.Como han mencionado otras respuestas, esto está técnicamente permitido por el estándar, pero es muy confuso y poco claro para los futuros lectores del código.
Esta es la razón por la que las
switch ... case
declaraciones generalmente deben escribirse con llamadas a funciones y no con mucho código en línea.switch(i) { case 0: do_zero_case(); do_general_stuff(); break; case 1: do_one_case(); do_general_stuff(); break; case 2: do_general_stuff(); break; default: do_default_not_zero_not_one_not_general_stuff(); break; }
fuente
do_general_stuff
predeterminado, solo para el caso 2 (y 0 y 1). Sini
embargo, nunca ejecuta el conmutador fuera del rango 0..2.do_general_stuff
por defecto, solo para el caso 2 (y 0 y 1).general
ydefault
fueron palabras diferentes. OTOH, es un hecho conocido que los humanos todavía pueden leer una palabra si las letras del medio están codificadas; Tendemos a mirar el principio y el final, por lo que tener solo el medio es diferente probablemente no sea ideal para la capacidad de deslizamiento. Quizás elimine eldo_
prefijo.