Is there a useful case using a switch statement without braces?
If you use control structures in macros a switch
instead of if
comes handy since it has no dangling else
problem.
#define DEBUG_PRINT(...) switch (!debug_mode) case 0: fprintf(__VA_ARGS__)
With that you don't have surprises if a user of that macro puts this in an additional condition
if (unclear) DEBUG_PRINT(stderr, "This is really %unclear\n", unclear);
else {
// do something reasonable here
}
Such a debug macro has the advantage of being always compiled (and then eventually optimized out). So the debug code has to remain valid through all the live time of the program.
Also observe here that it is important that the switch
doesn't use {}
, otherwise the if/else
example wouldn't work either. All this could be achieved by other means (if/else
, (void)0
and do/while
tricks) but this one is the most convenient I know of.
And don't take me wrong, I don't say that everybody should use control structures inside macros, you certainly should know what you are doing. But there are situations where it is justified.
Here's an example written by Dennis Ritchie in 1972 during his work on the first C compiler. The c02.c module, linked at the foot of page I just linked to, includes
easystmt()
{
extern peeksym, peekc, cval;
if((peeksym=symbol())==20) /* name */
return(peekc!=':'); /* not label */
if (peeksym==19) { /* keyword */
switch(cval)
case 10: /* goto */
case 11: /* return */
case 17: /* break */
case 18: /* continue */
return(1);
return(0);
}
return(peeksym!=2); /* { */
}
From reading his 1972 code it's clear Dennis was a fan of switch statements - he used them quite a bit. It's not so surprising given that almost everything was encoded as an int partly for lack of other data type possibilities. His compiler implementation used no structs at that stage because he was just in the middle of adding them to the language. Dynamic dispatch, vtables and polymorphism were a long way off. I've tried and failed to find a reference for this but if I recall correctly Dennis "invented" switch statements or at least contributed ideas leading to the form they take in C and considered them one of his best or proudest additions to the language.
The ability to leave out the braces makes switch statements formally similar to if
, for
, do
and while
statements, helping to simplify and unify the grammar. See the selection-statement and iteration-statement productions in the C grammar (e.g. in Appendix A13 of Kernighan and Ritchie, pages 236-237 in my copy) where these things are defined.
Obviously one can always add braces but maybe that seems heavy for such simple examples as this one. This example could be coded as a disjunctive if statement but I think one of the ideas Dennis had for switch was that the compiler is more clearly being offered the opportunity to optimise the implementation of the branching logic based on the particular constants involved.
I've thought of another case.
Suppose I have a counter of type unsigned char indicating the number of iterations of a loop, but if the counter equals zero, it needs to go through the loop 256 times. If my thinking is correct, you could code this as follows:
uint8_t counter;
/* counter will get its value here somewhere */
switch (counter)
default:
while (0 < counter)
{
case 0:
/* Perform action */
counter--;
}
This of course assumes that underflow from 0x00 results in 0xFF for an unsigned char. But it does for all my environments, even though PC Lint will complain...
And yes, it contains braces, but just for the while
, not for the switch
. If you know something better, let me hear it!
Would I program like this? Never! ... well, on a small 8-bit processor I even might! :-)