switch case 语句内部变量定义

switch case语句是非常常用的语句,入门的码农也知道是做什么的。

但关于switch case内定义变量的问题,网上的很多博文都有谬误,在这里我写一下对这个语句的了解。


先看合法的定义方式:

int main(int argc, const char * argv[]) {
    int idx = 2;
    switch (idx) {
            int k;
        case 1:
            int j;
            break;
        case 2:
            k = 1;
            j = 2;
            std::cout<<"K:"<<k<<std::endl;
            std::cout<<"J:"<<j<<std::endl;
            break;
        default:
            break;
    }
    return 0;
}


在C++11 std Dialect下 打印出的结果是:

K:1
J:2


然后看看不合法的写法:

int main(int argc, const char * argv[]) {
    int idx = 2;
    switch (idx) {
            int k = 1;
        case 1:
            int j = 1;
            break;
        case 2:
            k = 1;
            j = 2;
            std::cout<<"K:"<<k<<std::endl;
            std::cout<<"J:"<<j<<std::endl;
            break;
        default:
            break;
    }
    return 0;
}

编译无法通过。


解释下原因:

一为什么合法?

首先一个变量有没有被定义是在编译时就检查过的,因此这里可以编译通过。

其次在处理switch case语句中,C++11标准的编译器都会在执行case跳转前为变量分配空间,因此执行也没有问题。

(当然我并不建议在case语句外定义变量,因为何时为变量分配空间是编译器特性,而非语言特性,虽然这个问题中遵守C++11标准的编译器没有问题)

二为什么不合法?

C++11标准禁止这种写法。在编译时,编译器就会报错。C++11禁止这种写法的原因来自于C++的一个规定:

It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a local variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has POD type (3.9) and is declared without an initializer. (The transfer from the condition of a switch statement to a case label is considered a jump in this respect.)

众所周知,C++不允许使用未初始化的变量,而初始化操作和定义变量对于编译器来说是两码事,初始化操作是一个确确实实的在运行时才会被调用的语句,是可以被case跳转屏蔽掉的语句,而定义则是在编译器就完成检查的。

如果二的写法合法的话,那么会发生这样的问题:

编译时定义变量被执行,初始化和赋值语句也用各自的方式编译完成,并且在运行时,程序也的确为此变量分配了空间。但是在运行时,初始化语句却在某些情况下被跳转掉了。

虽然对于int等类型的变量,赋值和初始化在我们看来都是"=",但编译后的二进制是完全不同的,编译器会在编译时把"int j = 1;"编译成初始化,而把"j = 1;"编译成赋值。因此在整个运行过程中,如果初始化语句被case跳转掉了,我们在其他case语句中的"="不可能对此变量进行初始化。

这时,如果在整个switch(){}的定义域中,有对此变量的调用,那就是『试图在初始化一个变量前使用它』,因此C++11禁止了这种写法。


额外谈一些:

如果不在case中加上{},整个switch(){}都是使用同一个作用域,这一点通过上文符合语法例子中对J、K的定义和使用就能看出来。最好的方法就是在编码时,将整个switch语句用到的变量在switch外声明,并且针对某个case需要单独使用变量的情况,用{}明确此case语句的作用域

case的实现与goto非常相似,case的本质是一种标签,在switch case语句中变量的定义问题可以推广到goto语句中。

下面的代码也是不合法的,因为string是一个类,类有自己的隐式初始化方法,实际上这依然是个可能被跳转掉的初始化语句。

        case 1:
            std::string tempStr;
            break;









评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值