[c] Switch statement: must default be the last case?

Consider the following switch statement:

switch( value )
{
  case 1:
    return 1;
  default:
    value++;
    // fall-through
  case 2:
    return value * 2;
}

This code compiles, but is it valid (= defined behavior) for C90/C99? I have never seen code where the default case is not the last case.

EDIT:
As Jon Cage and KillianDS write: this is really ugly and confusing code and I am well aware of it. I am just interested in the general syntax (is it defined?) and the expected output.

This question is related to c switch-statement

The answer is


It's valid, but rather nasty. I would suggest it's generally bad to allow fall-throughs as it can lead to some very messy spaghetti code.

It's almost certainly better to break these cases up into several switch statements or smaller functions.

[edit] @Tristopia: Your example:

Example from UCS-2 to UTF-8 conversion 

r is the destination array, 
wc is the input wchar_t  

switch(utf8_length) 
{ 
    /* Note: code falls through cases! */ 
    case 3: r[2] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x800; 
    case 2: r[1] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x0c0; 
    case 1: r[0] = wc;
}

would be clearer as to it's intention (I think) if it were written like this:

if( utf8_length >= 1 )
{
    r[0] = wc;

    if( utf8_length >= 2 )
    {
        r[1] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x0c0; 

        if( utf8_length == 3 )
        {
            r[2] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x800; 
        }
    }
}   

[edit2] @Tristopia: Your second example is probably the cleanest example of a good use for follow-through:

for(i=0; s[i]; i++)
{
    switch(s[i])
    {
    case '"': 
    case '\'': 
    case '\\': 
        d[dlen++] = '\\'; 
        /* fall through */ 
    default: 
        d[dlen++] = s[i]; 
    } 
}

..but personally I would split the comment recognition into it's own function:

bool isComment(char charInQuestion)
{   
    bool charIsComment = false;
    switch(charInQuestion)
    {
    case '"': 
    case '\'': 
    case '\\': 
        charIsComment = true; 
    default: 
        charIsComment = false; 
    } 
    return charIsComment;
}

for(i=0; s[i]; i++)
{
    if( isComment(s[i]) )
    {
        d[dlen++] = '\\'; 
    }
    d[dlen++] = s[i]; 
}

The default condition can be anyplace within the switch that a case clause can exist. It is not required to be the last clause. I have seen code that put the default as the first clause. The case 2: gets executed normally, even though the default clause is above it.

As a test, I put the sample code in a function, called test(int value){} and ran:

  printf("0=%d\n", test(0));
  printf("1=%d\n", test(1));
  printf("2=%d\n", test(2));
  printf("3=%d\n", test(3));
  printf("4=%d\n", test(4));

The output is:

0=2
1=1
2=4
3=8
4=10

It's valid and very useful in some cases.

Consider the following code:

switch(poll(fds, 1, 1000000)){
   default:
    // here goes the normal case : some events occured
   break;
   case 0:
    // here goes the timeout case
   break;
   case -1:
     // some error occurred, you have to check errno
}

The point is that the above code is more readable and efficient than cascaded if. You could put default at the end, but it is pointless as it will focus your attention on error cases instead of normal cases (which here is the default case).

Actually, it's not such a good example, in poll you know how many events may occur at most. My real point is that there are cases with a defined set of input values where there are 'exceptions' and normal cases. If it's better to put exceptions or normal cases at front is a matter of choice.

In software field I think of another very usual case: recursions with some terminal values. If you can express it using a switch, default will be the usual value that contains recursive call and distinguished elements (individual cases) the terminal values. There is usually no need to focus on terminal values.

Another reason is that the order of the cases may change the compiled code behavior, and that matters for performances. Most compilers will generate compiled assembly code in the same order as the code appears in the switch. That makes the first case very different from the others: all cases except the first one will involve a jump and that will empty processor pipelines. You may understand it like branch predictor defaulting to running the first appearing case in the switch. If a case if much more common that the others then you have very good reasons to put it as the first case.

Reading comments it's the specific reason why the original poster asked that question after reading Intel compiler Branch Loop reorganisation about code optimisation.

Then it will become some arbitration between code readability and code performance. Probably better to put a comment to explain to future reader why a case appears first.


There's no defined order in a switch statement. You may look at the cases as something like a named label, like a goto label. Contrary to what people seem to think here, in the case of value 2 the default label is not jumped to. To illustrate with a classical example, here is Duff's device, which is the poster child of the extremes of switch/case in C.

send(to, from, count)
register short *to, *from;
register count;
{
  register 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);
  }
}

The case statements and the default statement can occur in any order in the switch statement. The default clause is an optional clause that is matched if none of the constants in the case statements can be matched.

Good Example :-

switch(5) {
  case 1:
    echo "1";
    break;
  case 2:
  default:
    echo "2, default";
    break;
  case 3;
    echo "3";
    break;
}


Outputs '2,default'

very useful if you want your cases to be presented in a logical order in the code (as in, not saying case 1, case 3, case 2/default) and your cases are very long so you do not want to repeat the entire case code at the bottom for the default


Chiming in with another example: This can be useful if "default" is an unexpected case, and you want to log the error but also do something sensible. Example from some of my own code:

  switch (style)
  {
  default:
    MSPUB_DEBUG_MSG(("Couldn't match dash style, using solid line.\n"));
  case SOLID:
    return Dash(0, RECT_DOT);
  case DASH_SYS:
  {
    Dash ret(shapeLineWidth, dotStyle);
    ret.m_dots.push_back(Dot(1, 3 * shapeLineWidth));
    return ret;
  }
  // more cases follow
  }

One scenario where I would consider it appropriate to have a 'default' located somewhere other than the end of a case statement is in a state machine where an invalid state should reset the machine and proceed as though it were the initial state. For example:

switch(widget_state)
{
  default:  /* Fell off the rails--reset and continue */
    widget_state = WIDGET_START;
    /* Fall through */
  case WIDGET_START:
    ...
    break;
  case WIDGET_WHATEVER:
    ...
    break;
}

an alternative arrangement, if an invalid state should not reset the machine but should be readily identifiable as an invalid state:

switch(widget_state) { case WIDGET_IDLE: widget_ready = 0; widget_hardware_off(); break; case WIDGET_START: ... break; case WIDGET_WHATEVER: ... break; default: widget_state = WIDGET_INVALID_STATE; /* Fall through */ case WIDGET_INVALID_STATE: widget_ready = 0; widget_hardware_off(); ... do whatever else is necessary to establish a "safe" condition }

Code elsewhere may then check for (widget_state == WIDGET_INVALID_STATE) and provide whatever error-reporting or state-reset behavior seems appropriate. For example, the status-bar code could show an error icon, and the "start widget" menu option which is disabled in most non-idle states could be enabled for WIDGET_INVALID_STATE as well as WIDGET_IDLE.


yes, this is valid, and under some circumstances it is even useful. Generally, if you don't need it, don't do it.


There are cases when you are converting ENUM to a string or converting string to enum in case where you are writing/reading to/from a file.

You sometimes need to make one of the values default to cover errors made by manually editing files.

switch(textureMode)
{
case ModeTiled:
default:
    // write to a file "tiled"
    break;

case ModeStretched:
    // write to a file "stretched"
    break;
}