In C, dove sembra essere l'origine, il blocco di codice dell'istruzione switch
non è un costrutto speciale. È un normale blocco di codice, proprio come un blocco sotto un'istruzione if
.
switch ()
{
}
if ()
{
}
case
e default
sono etichette di salto all'interno di questo blocco, in particolare relative a switch
. Vengono gestiti come normali etichette di salto per goto
. C'è una regola specifica che è importante qui: le etichette Jump possono essere quasi ovunque nel codice, senza interrompere il flusso del codice.
Come un normale blocco di codice, non è necessario che sia una dichiarazione composta. Anche le etichette sono opzionali. Queste sono dichiarazioni switch
valide in C:
switch (a)
case 1: Foo();
switch (a)
Foo();
switch (a)
{
Foo();
}
Lo standard C stesso fornisce questo esempio (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);
}
In the artificial program fragment, the object whose identifier is i exists
with automatic storage duration (within the block) but is never initialized,
and thus if the controlling expression has a nonzero value, the call to the
printf function will access an indeterminate value. Similarly, the call to the
function f cannot be reached.
Inoltre, default
è anche un'etichetta di salto e quindi può essere ovunque, senza la necessità di essere l'ultimo caso.
Questo spiega anche il dispositivo di 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);
}
Perché il fall-through? Poiché nel normale flusso di codice in un normale blocco di codice, l'istruzione successiva alla successiva è prevista , proprio come ci si aspetterebbe in un blocco di codice 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();
}
La mia ipotesi è che la ragione di ciò sia la facilità di implementazione. Non hai bisogno di codice speciale per analizzare e compilare un blocco switch
, avendo cura di regole speciali. Lo analizzi come qualsiasi altro codice e devi solo preoccuparti delle etichette e della selezione del salto.
Una domanda di follow-up interessante da tutto ciò è se le seguenti istruzioni nidificate stampano "Fatto". oppure no.
int a = 10;
switch (a)
{
switch (a)
{
case 10: printf("Done.\n");
}
}
Lo standard C si prende cura di questo (6.8.4.2.4):
A case or default label is accessible only within the closest enclosing switch statement.