[Someone wrote] ...
Were you being literal with the above statement? Cannot find any reference
to a switch statement being used to return a value. All info I find
discusses only the form I'm used to:
case 1: {x = 0; break;}
case 2: {x = 1; break;}
I suspect you think that switch/case constructs are quite restricted
(which is often true in other languages). C is a bit lower level
than that -- a switch is just a goto in disguise:
volatile unsigned char *dev;
unsigned char *mem;
...
i = n / 8;
switch (n % 8) {
do {
*dev = *mem++;
case 7: *dev = *mem++;
case 6: *dev = *mem++;
case 5: *dev = *mem++;
case 4: *dev = *mem++;
case 3: *dev = *mem++;
case 2: *dev = *mem++;
case 1: *dev = *mem++;
case 0: ;
} while (i-- != 0);
}
This construct, called "Duff's Device" after Tom Duff (see the
FAQ), is entirely valid Standard C. The "switch" is just a goto,
and each "case" label is just a target label. (The FAQ's version
is slightly different -- I looked it up after typing in the above.)
The only "magic" about switch/case is that a case "looks upwards"
in enclosing brace scope blocks to find the innermost enclosing
"switch" statement, and places the appropriate "if (switch_expr ==
this_case_constant) goto here" up there. (Old non-optimizing
C compilers actually implemented this by compiling:
switch (expr) {
...
}
as if it were:
tmp = expr;
goto just_past_end_of_switch;
...
goto around;
just_past_end_of_switch:
if (tmp == first_value) goto first_label;
if (tmp == second_value) goto second_label;
...
if (tmp == last_value) goto last_label;
if (there was a default) goto default_label;
around:
This allows the compiler to "forget" the code in between, and
remember only the <value,label> pairings. The <value,label>
pairs can also be compared more efficiently than with a straight
sequence of "if"s; e.g., if the table is dense this turns into:
if (tmp >= first_value && tmp <= last_value)
goto label[tmp - first_value];
if (there was a default)
goto default_label;
around:
and in other cases the compiler could generate an inline
binary search.)
The fact that "case" labels are really just goto-labels is
also the (or at least "a") logical reason behind the requirement
for a "break" statement if you did not want to fall through
from one case to the next. Just as:
if (x == 1) goto label;
f();
label:
g();
executes g() even when x == 2, so does a switch/case.