Recently I found out that the body of a switch can be any statement (C99 6.8.4). The idea was first suggested to me by this: https://stackoverflow.com/a/9220598/515212
So one can have switch statements like
void f(int n)
{
switch (n)
case 0:
printf("zero\n");
}
or even put ifs, whiles, etc.
void f(int n)
{
switch (n)
if (1)
{
case 0:
printf("zero\n");
}
else
while (--n)
{
default:
printf("non-zero\n");
}
}
Just out of interest, I was wondering whether this syntax has some usage or is just an artifact of how the switch statement is defined in the standard?
You can consider the switch statement as a code block with labels (case(s) are indeed labels) where the control is passed with a goto statement.
Something like
void f(int n)
{
if ( n == 0 ) goto Label_case_0;
else goto Label_default;
{
if ( 1 )
{
Label_case_0:
printf("zero\n");
}
else
while (--n)
{
Label_default:
printf("non-zero\n");
}
}
}
In my opinion it is not a good idea to place case labels inside some other control structures because this makes the code difficult to read and can lead to errors.
This is valid C code. It origins from assembly where every conditional statement uses if, goto and label jumps.
Implementation of array copy using this feature is called Duff's Device
void copy(char *from, char *to, int count)
{
int n = (count + 7) / 8;
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);
}
}
When you replace while with if and goto
void copy(char *from, char *to, int count)
{
int n = (count + 7) / 8;
switch(count % 8) {
case 0:
loop: *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++;
if(--n > 0) goto loop;
}
}
Then replace switch with if and goto
void copy(char *from, char *to, int count)
{
int n = (count + 7) / 8;
if(count%8==7)goto case7;
if(count%8==6)goto case6;
if(count%8==5)goto case5;
if(count%8==4)goto case4;
if(count%8==3)goto case3;
if(count%8==2)goto case2;
if(count%8==1)goto case1;
if(count%8==0)goto case0; // this can be omitted
case0: // this can be omitted
loop: *to++ = *from++;
case7: *to++ = *from++;
case6: *to++ = *from++;
case5: *to++ = *from++;
case4: *to++ = *from++;
case3: *to++ = *from++;
case2: *to++ = *from++;
case1: *to++ = *from++;
if(--n > 0) goto loop;
}
Which is functionally (almost) equivalent to
void copy(char *from, char *to, int count)
{
while(--n > 0) {
*to++ = *from++;
}
}
It's almost equivalent because in the last implementation loop check is performed 8 times more often, what have impact on performance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With