C/C++ switch statements, fall out?

C/C++ switch statements, we all know how they work right? How can you do the following in one switch statement? (Without comparing cmd->cmd again that is).

switch(cmd->cmd)
{
case W1_CMD_SEARCH:
    ScanBusResult(cn->seq, msg->id.mst.id);
    break;
case W1_CMD_LIST_SLAVES:
    KernelDevicesResult(cn->seq, msg->id.mst.id);
    break;
default:
    cout << "cmd->len " << cmd->len
        << " ignore kernel ack for "
        << ToString((w1_commands)cmd->cmd) << endl;
}

switch(cmd->cmd)
{
    case W1_CMD_SEARCH:
    case W1_CMD_LIST_SLAVES:
        cout << "cmd->len " << cmd->len << ' '
            << ToString((w1_commands)cmd->cmd)
            << " slave listing complete\n";
}

This is a usage I've never seen before in the C++ switch statement. I did at one point see some code that had a if statement enclosing some case statements and I thought that's cool, you can conditionally enable case statements, but when I tried that code it didn't work, so I don't know what that was about. Interestingly when I was reading about JavaScript and how their switch statements worked it got me thinking about C++ and if I really understood what a case statement was. The answer was I knew it by example, a list of case statements inside a switch statement, with possible fall through, which covers pretty much every switch statement I've ever seen. I had been told that the implementation will be faster if the list of case statements are continuous and in order, so that the compiler can generate a jump table to quickly lookup where to jump to, instead of testing each case, but I guess I never paid addition to what was really going on to fully make use of it.

But some how looking at JavaScript got me thinking about C++'s switch. So I played around, and found that the case statements behave just as if you were sprinkling around jump targets for a goto statement, only the scope is limited to a switch statement, and there are limits to creating variables that cross case statements. I thought the jump label was interesting to know, but couldn't think of a practical use of it. It took a while, but then I was coding one day and found one. Traditionally a switch statement is used in a combination of one of two ways, execute a different set of statements per case statement (with break), or execute the same set of statements with multiple case statements (fall through). I was wanting to do both, to execute a different set of statements per case, and do a common set of statements for a set of case statements. One option is to use multiple switch statements, one for the exclusive, one for the common. But it turns out by knowing case is a goto target, you can do both, and here is the above code rewritten to the version in the program I'm working on.

switch(cmd->cmd)
{
    do {
    case W1_CMD_SEARCH:
        ScanBusResult(cn->seq, msg->id.mst.id);
        break;
    case W1_CMD_LIST_SLAVES:
        KernelDevicesResult(cn->seq, msg->id.mst.id);
        break;
    } while(0);
    cout << "cmd->len " << cmd->len << ' '
        << ToString((w1_commands)cmd->cmd)
        << " slave listing complete\n";
    break;
default:
    cout << "cmd->len " << cmd->len
        << " ignore kernel ack for "
        << ToString((w1_commands)cmd->cmd) << endl;
}

The switch statement will jump to one of three locations. Two of those happen to be inside a do ... while(0) statement. That inner (non-repeating) loop means the break no longer goes out of the switch statement, but rather it will just exit the loop. For instance W1_CMD_SEARCH, will call ScanBusResult, then break down to the cout line, then break out of the switch statement.

It's an interesting way to execute unique statements per case, and yet still be able to group those to execute statements that should be common to a set of cases.


Written by David Fries <david@fries.net>

Valid HTML 4.0! Valid HTML 4.0!
My pgp key is available and the fingerprint follows. See
http://www.gnupg.org/ for details.
pub 1024D/CB1EE8F0 2001-08-21 David D. Fries <david@fries.net>
Key fingerprint = 7079 F7EA D7EA 8E93 5B84 1900 008F 39D9 CB1E E8F0
sub 1024g/D9B8B029 2001-08-21
Don't e-mail 171484e3_594f2e5a at spamcheck aerospace fries net */?>