Main Content

MISRA C++:2023 Rule 9.4.2

The structure of a switch statement shall be appropriate

Since R2024b

Description

Rule Definition

The structure of a switch statement shall be appropriate.

Rationale

Using an appropriate structure for a switch statement enforces consistency. The MISRA™ C++: 2023 standard defines certain restrictions on the structure of switch statements for them to be considered appropriate. Adhering to this structure can avoid problems such as unreachable code and unintentional fall-through causing unexpected results.

A switch statement consists of these elements:

  • Switch body — The set of statements enclosed in curly braces after the switch condition.

  • Switch label group — The labels that introduce a sequence of statements within a switch statement. A switch label group can consist of one or more case labels, or the default label, and appears only in the outermost level of the switch body.

  • Switch branch — The group of statements that comprise a single branch of execution in a switch statement. The switch branches in a switch statement partition the switch body. A switch label group begins each switch branch.

For example:

switch (condition) { // Switch body starts
	// Switch branch 1
	case 1: // Switch label group 1, starts with case labeled statement 
		std::cout << "Number is One";
		break;

	// Switch branch 2
	case 2: case 3:// Switch label group 2
		std::cout << "Number is Two or Three"; 
		break;

	// Switch branch 3
	default: // Switch label group 3
		std::cout << "Number is something else";
		break;
}

An appropriately structured switch statement meets these criteria:

  • A simple declaration can optionally appear before the condition. Expression statements, such as function calls, are not permitted.

  • Case labels and default labels appear only at the outermost level of the switch body as part of a switch label group. Using case or default labels inside a nested block within the switch body can result in unstructured code.

  • Switch label groups use only case and default labels. Using other labels can introduce unstructured control flow.

  • The switch body starts with a switch label group. Any other statement placed before a switch label group is an uninitialized variable or unreachable code.

  • Each switch branch is explicitly terminated. Failing to terminate a switch branch allows unintentional fallthrough to occur. Acceptable ways to terminate a switch branch are:

    • a break statement

    • a continue statement

    • a return statement

    • a goto statement

    • a throw expression

    • a call to a [[noreturn]] function

    • a [[fallthrough]] attribute applied to a null statement

  • The switch body has at least two switch branches. Using only a single switch branch can indicate a programming error.

  • The switch body has a switch branch with a default label. Having a default is defensive programming because it accounts for situations where no case is selected.

    As an exception, you can omit a default label when the type of the condition is an unscoped enumeration with no fixed underlying type. In this situation, a default is not required if all enumerators are listed as case labels. For example:

    enum Colors { YELLOW, RED, BLUE } color;    
    
    switch (color)      // Compliant
    {
      case YELLOW:
      case RED:
        break;
      case BLUE:
        break;
    }

Polyspace Implementation

Polyspace® reports a violation of this rule if a switch statement fails to meet any of the criteria for being considered an appropriate switch statement. For example, Polyspace flags any of these circumstances:

  • Adding a function call before the condition of a switch statement

  • Using a case or default label anywhere besides the beginning of a switch branch

  • Using a label other than case or default in a switch label group

  • Adding code before a switch label group

  • Not terminating a switch branch with one of the acceptable statements, expressions, or attributes

  • Having a switch statement with a single switch branch

Troubleshooting

If you expect a rule violation but Polyspace does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

#include <iostream>

int main() {                                
	int month, year, days;

	std::cout << "Enter month (1-12): ";
	std::cin >> month;
	std::cout << "Enter year: ";
	std::cin >> year;

	switch (month) {                        // Noncompliant
		case 4: case 6: case 9: case 11:    // Noncompliant
			days = 30;
		case 2:
			// Check for leap year
			if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
				days = 29;
			} else {
				days = 28;
			}
			break;
		case: 1: case: 3: case: 5: case: 7 case 8: case 10: case 12:
			days = 31;
			break;
	}
	int result = days;

    return 0;
}

This example contains two different ways the structure of a switch statement can be noncompliant:

  • There is no default case. This is problematic because the code does no input checking on the switch condition month. The user can enter a value that is not covered by any case and there is no default to handle the value.

  • The switch branch for case 4: case 6: case 9: case 11: fails to terminate properly. In this situation, the switch branch fallsthrough to case 2. The switch statement sets the value of days incorrectly to 29 or 28 if the value of month is 4, 6, 9, or 11.

#include <iostream>

int main() {
    int month, year, days;

    std::cout << "Enter month (1-12): ";
    std::cin >> month;
    std::cout << "Enter year: ";
    std::cin >> year;

    switch (month) {                      // Compliant
        case 4: case 6: case 9: case 11:
            days = 30;
            break;      // Added break statement
        case 2:
            // Check for leap year
            if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
                days = 29;
            } else {
                days = 28;
            }
            break;
        default:        // Added default case
            days = 31;
	      break;
    }

    int result = days;

    return 0;
}

With the addition of a default and a break statement, you can make the structure of the switch appropriate.

Check Information

Group: Statements
Category: Required

Version History

Introduced in R2024b