开关盒中的局部范围

时间:2015-10-21 09:54:37

标签: c++

我看到了一些令人惊讶的代码:

#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;
}

它在没有警告的情况下编译和运行。案例1 {}的括号似乎被忽略了。

  

myDummy(1)

     

- &GT; 1

     

myDummy(2)

     

- &GT; 2

如果我将案例1的代码修改为:

             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;

然后它不再编译:

  

prog.cpp:16:13:错误:跳转到案例标签[-fpermissive]

    case 2:

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

             int a = i;

案例1的括号:{}中断;不要取消开关上下文。它只是为变量创建了一个局部范围。 但这真的很混乱。 为什么会出现这种行为?

3 个答案:

答案 0 :(得分:3)

以下是关于switch(§6.4.2,强调我的)标准的说法:

  

2 - 任何声明   开关   声明可以用一个或多个案例标签标记为   如下:   案件   常数表达式   :   在哪里   常数表达式   应该是转换的常量表达式(   5.19   )推广类型的   切换条件。

     

&LT; ...&GT;

     

5 - 当   开关   执行语句,评估其条件并与每个案例常量进行比较。如果   其中一个case常量等于condition的值,control被传递给下面的语句   匹配的案例标签

因此switch并不关心案件的确切位置,以下是有效的:

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;
}

关于您提出的修改,请查看我对this question的回答。基本上用

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;
 }

您可以跳转到case2而无需实际创建a,但a仍然在范围内。

答案 1 :(得分:2)

您可以在任何地方放置范围:

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

但是你不能把变量初始化放在一个范围内,超过2个开关可以看到它:

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

最后,在另一个范围内的案例标签没有任何问题(只要它不违反我们的第二个规则,那里):

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

答案 2 :(得分:2)

在移动到不同的范围块时,

switch与标签的工作方式与goto的标签相同。

采用这样的方案时应该小心,特别是在读取未初始化的变量时,其行为是未定义的。