Publications
of Jon Jagger
jon@jaggersoft.com
Appeared in CVu 9.1, Nov 1996

{ yourself }
switch

Can you spot the problem with this code?

switch (day_of_week()) 
{
defualt     : /*...*/ break;
case monday : /*...*/ break;
case tuesday: /*...*/ break;
...
}
It's not the fact that the default is at the top. That's perfectly legal. The fault is that default is spelled incorrectly. Yet it compiles without error. What's going on? The answer is that the defualt: is being seen by the compiler as a goto label! Does your compiler issue a warning for this? A colour syntax highlighter would be a useful in this situation.

For the next error I can imagine Sherlock Holmes, crouched over a keyboard, debugging C code. Eventually he tracks the bug to a case without a break...

switch (day_of_week()) 
{
case monday : /*...*/
case tuesday: /*...*/ break;
...
default: /*...*/ break;
}
In this code, if expression is equal to monday then the flow of control will pass to case monday:. However, since there is no break with that case, the flow of control passes straight on to case tuesday. That does have a break, so after tuesdays code has finished, the flow of control finally passes to the end of the switch statement. No doubt Dr.Watson would chronicle this as "The case of the missing break". ;-} [1] [2]

Sometimes you want to create a variable for use just inside a switch. You could do this...

int sect;
/* 20 lines of code here */
switch (day_of_week()) 
{
...
}
...but following good practice you declare the variable in its innermost scope, and write this...
switch (day_of_week()) 
{
int sect;
case monday:
...
}
The danger is that it's now a very short step to this...
switch (day_of_week()) 
{
int sect = beetle();
case monday:
...
}
The flow of control will never call beetle(), so if the code assumes sect will be correctly initialized by beetle() , then tough, because it won't be.

Finally you can't have two cases with the same constant.

switch (penny(lane)) 
{
case 0:
case 0:
}
This just won't compile. Strangely, this can be useful. It's yet another way to implement a compile time assertion.
#define COMPILE_TIME_ASSERT(predicate)       \
    switch(0){case 0:case predicate:;}
Now if predicate evaluates to true (i.e., 1) then the case labels will be 0 and 1. Different. Ok. If predicate evaluates to false (i.e., 0) then the case labels will be 0 and 0. The same. Compile time error.
#include <limits.h>

#define CHECK_BITSIZE(type, size)        \
    COMPILE_TIME_ASSERT(sizeof(type) * CHAR_BIT == size)

void check_int_bitsizes(void)
{
	CHECK_BITSIZE(char,  8);
	CHECK_BITSIZE(int,  16);
	CHECK_BITSIZE(long, 32);
}

That's all for now.
Cheers
Jon Jagger
jon@jaggersoft.com

[1] See "Silver Blaze".

[2] The infamous "phone network crash" that hit Los Angeles, San Francisco, Washington D.C., etc, in June 1991 was tracked to a case without a break. However, sometimes a missing break is not an error. For example Duffs Device, but that's another story.