Darius Zu CH
Darius Zu CH

Reputation: 145

local scope in switch case

I saw some surprising code:

#include <iostream>
using namespace std;

int main() {
    // your code goes here
    auto myDummy = [](int i){
    switch(i){
        case 0: return 0;
        case 1:{
            std::cout << "Evaluated 1\n";
            if(i == 1){
                return 1;
            }
            case 2:
            std::cout << "Evaluated 2\n";
            return 2;
        }
        break;
        default: return -1;
    }
    };
    std::cout << myDummy(1) << "\n";
    return 0;
}

It compiles and run without warning. The bracket of case 1{} seems to be ignored.

myDummy(1)

-> 1

myDummy(2)

-> 2

If I modify the code for case 1 to be:

             case 1:{
                std::cout << "Evaluated 1\n";
                int a = i;
                if(a == 1){
                    return 1;
                }
                case 2:
                std::cout << "Evaluated 2\n";
                return 2;
            }
            break;

then it does not compile anymore:

prog.cpp:16:13: error: jump to case label [-fpermissive]

    case 2:

         ^ prog.cpp:12:21: note:   crosses initialization of 'int a'

             int a = i;

The brackets for case 1:{}break; do not cancel the switch context. It just creates a local scope for variable. But this is really obfuscating. Why such a behaviour?

Upvotes: 4

Views: 1607

Answers (3)

Bathsheba
Bathsheba

Reputation: 234865

switch to a label works in an identical way to goto with a label when it comes to moving to a different scope block.

You should take care when adopting such a scheme, in particular with regards to reading uninitialised variables, the behaviour of which is undefined.

Upvotes: 3

Not a real meerkat
Not a real meerkat

Reputation: 5739

You can place a scope anywhere:

int main() {
    int a;
    {
        int a; // in a more local scope.
    }
}

But you can't put a variable initialization in a scope where it would be visible by more than 2 cases of a switch:

int main() {
    int b;
    switch(1) {
    case 0:
        int a = 0; // error
        break;
    case 1:
        b = a; // what happens?
        break;
    }
}

Finally, there's nothing wrong with a case label inside another scope (as long as it would not violate our second rule, there):

int main() {
  switch(1) {
  case 1: {
    break;
  case 2:
    break;
    }
  }
}

Upvotes: 2

SingerOfTheFall
SingerOfTheFall

Reputation: 29976

Here's what the standard says about a switch (§6.4.2, emphasis mine):

2 - Any statement within the switch statement can be labeled with one or more case labels as follows: case constant-expression : where the constant-expression shall be a converted constant expression ( 5.19 ) of the promoted type of the switch condition.

<...>

5 - When the switch statement is executed, its condition is evaluated and compared with each case constant. If one of the case constants is equal to the value of the condition, control is passed to the statement following the matched case label

So the switch doesn't care where exactly the cases are, the following works:

int main() {
    int i = 0;
    switch(i)
    {
        case 1:
        {
        case 2:
            {
                if(false)
                {
                    case 0:
                        std::cout << "hello there!"; //yes it will print
                }
            }
        }
    }

    return 0;
}

Regarding the modification you propose, check my answer to this question. Basically with

case 1:{
    std::cout << "Evaluated 1\n";
    int a = i;
    if(a == 1){
            return 1;
    }
    case 2:
    //here a is in scope
    std::cout << "Evaluated 2\n";
    return 2;
 }

you can jump to case2 without actually creating a, but a will still be in scope.

Upvotes: 3

Related Questions