En C, donde el origen parece ser, el bloque de código de la instrucción switch
no es una construcción especial. Es un bloque de código normal, al igual que un bloque en una declaración if
.
switch ()
{
}
if ()
{
}
case
y default
son etiquetas de salto dentro de este bloque, específicamente relacionadas con switch
. Se manejan igual que las etiquetas de salto normales para goto
. Hay una regla específica que es importante aquí: las etiquetas de salto pueden estar en casi todas partes del código, sin interrumpir el flujo de código.
Como bloque de código normal, no es necesario que sea una instrucción compuesta. Las etiquetas son opcionales, también. Estas son declaraciones de switch
válidas en C:
switch (a)
case 1: Foo();
switch (a)
Foo();
switch (a)
{
Foo();
}
El propio estándar de C da esto como ejemplo (6.8.4.2):
switch (expr)
{
int i = 4;
f(i);
case 0:
i=17;
/*falls through into default code */
default:
printf("%d\n", i);
}
En el fragmento de programa artificial, el objeto cuyo identificador es i existe
con duración de almacenamiento automático (dentro del bloque) pero nunca se inicializa,
y así, si la expresión de control tiene un valor distinto de cero, la llamada a la
La función printf accederá a un valor indeterminado. Del mismo modo, la llamada a la
No se puede alcanzar la función f.
Además, default
también es una etiqueta de salto, y por lo tanto puede estar en cualquier lugar, sin la necesidad de ser el último caso.
Esto también explica el dispositivo de Duff:
switch (count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while(--n > 0);
}
¿Por qué la caída? Debido a que en el flujo de código normal en un bloque de código normal, el paso a la siguiente declaración es esperado , tal como lo esperaría en un bloque de código if
.
if (a == b)
{
Foo();
/* "Fall-through" to Bar expected here. */
Bar();
}
switch (a)
{
case 1:
Foo();
/* Automatic break would violate expected code execution semantics. */
case 2:
Bar();
}
Mi conjetura es que la razón de esto fue la facilidad de implementación. No necesita un código especial para analizar y compilar un bloque switch
, cuidar de reglas especiales. Simplemente lo analiza como cualquier otro código y solo tiene que cuidar las etiquetas y la selección de salto.
Una pregunta de seguimiento interesante de todo esto es si las siguientes declaraciones anidadas se imprimen "Hecho". o no.
int a = 10;
switch (a)
{
switch (a)
{
case 10: printf("Done.\n");
}
}
El estándar C se preocupa por esto (6.8.4.2.4):
Se puede acceder a una etiqueta de caso o por defecto solo dentro de la declaración de cambio de cierre más cercana.