4

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?

Lundin
  • 195,001
  • 40
  • 254
  • 396
Darius Zu CH
  • 145
  • 1
  • 8

3 Answers3

3

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.

Community
  • 1
  • 1
SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105
3

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.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

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;
    }
  }
}
Not a real meerkat
  • 5,604
  • 1
  • 24
  • 55
  • fair... let me reformulate then: Doesn t it surprise you that case2 is taken into account? – Darius Zu CH Oct 21 '15 at 10:04
  • well, partially, thanks. my surprise was to see case2 being actually treated, while it was in a nested scope. My ignorance of how a switch work was the problem. I appreciate the explanation about variable initialization though. thanks. – Darius Zu CH Oct 21 '15 at 11:37
  • There is plenty of wrong with a case inside the scope of another case. There is never a reason to use such obscure program design, just because the language allows it doesn't make it good practice. – Lundin Oct 21 '15 at 13:03
  • @Lundin I didn't say it was a good practice. By saying "There's nothing wrong" I just meant that this is perfectly legal C++. – Not a real meerkat Oct 21 '15 at 13:07