Skip to content

21 Beginner The Hundred

One Scope for Every Case

one tidy local, and the case below it stops compiling

#include <iostream>

void apply(char op, int a, int b) {
    switch (op) {
    case '*':
        int product = a * b;   // a little local, just for this case
        std::cout << "product: " << product << '\n';
        break;
    case '+':
        std::cout << "sum: " << a + b << '\n';
        break;
    default:
        std::cout << "unknown operator\n";
    }
}

Compile it. What happens?

Answer

It doesn't compile — and the error points at case '+':, a line that does nothing wrong.

Why

A switch has exactly one block: the braces after the condition. case '*': and case '+': are labels inside that block — jump targets, much like goto targets — not scopes of their own. So product is in scope from its declaration all the way to the switch's closing brace, and jumping to case '+': or default: would enter that scope past the initializer, leaving a live variable that was never initialized. The standard forbids such a jump, and GCC 11.5 explains it from both ends:

error: jump to case label
note:   crosses initialization of ‘int product’

Only initialization is fenced off, not visibility: drop the = a * b and int product; compiles, with product plainly visible — and indeterminate — inside case '+':. Reading it there is undefined behavior, though -Wall does warn: ‘product’ may be used uninitialized (-Wmaybe-uninitialized).

The fix

Give the case its own block — the braces cost one line and close the scope before the next label:

    case '*': {
        int product = a * b;
        std::cout << "product: " << product << '\n';
        break;
    }

Takeaway: case labels are jump targets, not scopes — a switch body is one scope, so any case that declares a variable needs its own braces.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo — add -DSHOW_BUG to meet the error.

Open in Compiler Explorer ↗ Open SHOW_BUG variant ↗ Quiz this entry