开关箱中的局部作用域

local scope in switch case

本文关键字:作用域 局部 开关箱      更新时间:2023-10-16

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

#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 1n";
            if(i == 1){
                return 1;
            }
            case 2:
            std::cout << "Evaluated 2n";
            return 2;
        }
        break;
        default: return -1;
    }
    };
    std::cout << myDummy(1) << "n";
    return 0;
}

编译并运行时没有警告。大小写1{}的括号似乎被忽略了。

myDummy (1)

-> 1

myDummy (2)

-> 2

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

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

则不再编译:

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;

第1种情况的括号:{}break;不要取消交换机上下文。它只是为变量创建了一个局部作用域。但这真的很令人困惑。为什么会有这样的行为?

以下是标准对switch(§6.4.2,重点是我的)的描述:

2 - 表中的任何语句开关语句可以用一个或多个case标签标记为如下:情况下常数表达式:在哪里常数表达式须为转换后的常数表达式(5.19)的提升型开关状态。

& lt;…>

5 -当开关语句执行时,计算其条件并与每个case常量进行比较。如果其中一个case常量等于条件的值,控制传递给后面的语句匹配的case标号

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

关于你提出的修改,请检查我对这个问题的回答。基本上是用

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

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

switch到标签的工作方式与goto与标签的工作方式相同,当涉及到移动到不同的作用域块时

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

你可以在任何地方设置作用域:

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

最后,在另一个作用域内使用case标签没有问题(只要它不违反我们的第二条规则):

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