The C++ switch Statement

The C++ switch statement allows selection among multiple sections of code, depending on the value of an expression. The expression enclosed in parentheses, the “controlling expression,” must be of an integral type or of a class type for which there is an unambiguous conversion to integral type. Integral promotion is performed as described in Integral Promotions in Chapter 3.

The switch statement causes an unconditional jump to, into, or past the statement that is the “switch body,” depending on the value of the controlling expression, the values of the case labels, and the presence or absence of a default label. The switch body is normally a compound statement (although this is not a syntactic requirement). Usually, some of the statements in the switch body are labeled with case labels or with the default label. Labeled statements are not syntactic requirements, but the switch statement is meaningless without them. The default label can appear only once.

Syntax

caseconstant-expression:statement

default:statement

The constant-expression in the case label is converted to the type of the controlling expression and is then compared for equality. In a given switch statement, no two constant expressions in case statements can evaluate to the same value. The behavior is shown in Table 5.1.

Table 5.1 Switch Statement Behavior

Condition Action
Converted value matches that of the promoted controlling expression. Control is transferred to the statement following that label.
None of the constants match the constants in the case labels; default label is present. Control is transferred to the default label.
None of the constants match the constants in the case labels; default label is not present. Control is transferred to the statement after the switch statement.

An inner block of a switch statement can contain definitions with initializations as long as they are reachable — that is, not bypassed by all possible execution paths. Names introduced using these declarations have local scope. The following code fragment shows how the switch statement works:

switch( tolower( *argv[1] ) )
{
    // Error. Unreachable declaration.
    char szChEntered[] = "Character entered was: ";

case 'a' :
    {
    // Declaration of szChEntered OK. Local scope.
    char szChEntered[] = "Character entered was: ";
    cout << szChEntered << "a\n";
    }
    break;

case 'b' :
    // Value of szChEntered undefined.
    cout << szChEntered << "b\n";
    break;

default:
    // Value of szChEntered undefined.
    cout << szChEntered << "neither a nor b\n";
    break;
}

A switch statement can be nested. In such cases, case or default labels associate with the most deeply nested switch statements that enclose them. For example:

switch( msg )
{
case WM_COMMAND:      // Windows command. Find out more.
    switch( wParam )
    {
    case IDM_F_NEW:   // File New menu command.
        delete wfile;
        wfile = new WinAppFile;
        break;
    case IDM_F_OPEN:  // File Open menu command.
        wfile->FileOpenDlg();
        break;
    ...
    }
case WM_CREATE:       // Create window.
    ...
    break;
case WM_PAINT:        // Window needs repainting.
    ...
    break;
default:
    return DefWindowProc( hWnd, Message, wParam, lParam );
}

The preceding code fragment from a Microsoft Windows® message loop shows how switch statements can be nested. The switch statement that selects on the value of wParam is executed only if msg is WM_COMMAND. The case labels for menu selections, IDM_F_NEW and IDM_F_OPEN, associate with the inner switch statement.

Control is not impeded by case or default labels. To stop execution at the end of a part of the compound statement, insert a break statement. This transfers control to the statement after the switch statement. This example demonstrates how control “drops through” unless a break statement is used:

BOOL fClosing = FALSE;

...

switch( wParam )
{
case IDM_F_CLOSE:       // File close command.
    fClosing = TRUE;
    // fall through

case IDM_F_SAVE:        // File save command.
    if( document->IsDirty() )
        if( document->Name() == "UNTITLED" )
            FileSaveAs( document );
        else
            FileSave( document );

    if( fClosing )
        document->Close();

    break;
}

The preceding code shows how to take advantage of the fact that case labels do not impede the flow of control. If the switch statement transfers control to IDM_F_SAVE, fClosing is FALSE. Therefore, after the file is saved, the document is not closed. However, if the switch statement transfers control to IDM_F_CLOSE, fClosing is set to TRUE, and the code to save a file is executed.