浅析C/C++中的switch/case陷阱

  先看下面一段代码:

  文件main.cpp

#include<iostream>
using namespace std; int main(int argc, char *argv[])
{
int a =;
switch(a)
{
case : int b=;cout<<b<<endl;break;
case : cout<<b<<endl;break;
default:break;
}
return ;
}

  在gcc编译器下编译的结果为:

  提示跳过了变量b的初始化过程。对于一个局部变量,它的作用域为它所定义的地方到它所在的语句块结束为止,那么对于变量b,它所在的最小语句块为switch{}块,那么也就说在case 0后面的部分,变量b都是可见的(注意在case 0之前变量b是无法访问的)。考虑这样一种情况,当a的值为1,那么程序就跳到case 1执行,此时b虽然可以访问,但是跳过了它的初始化过程。而如果在定义变量的同时进行了初始化,表明程序员希望初始化这个变量,但是此时跳过了该变量的初始化,就可能导致程序出现程序员无法意料的情况,因此编译器为了避免跳过这样的初始化而造成无法预料的结果,就对该语句进行报错。

  如果将上述代码改为:

 switch(a)
{
case : int b;b=0;cout<<b<<endl;break;
case : cout<<b<<endl;break;
default: break;
}

  编译的结果为:

  只是进行了警告,因为在定义变量的时候没有进行初始化,也就是说程序怎么执行都不会跳过变量的初始化过程,不会说由于跳过了该过程而造成无法预料的错误或程序崩溃现象。因此只是进行了警告。

  再看下面这段代码:

 switch(a)
{
case : break;
default: int b=;cout<<b<<endl;break;
}

  这段代码没有报错。因为如果执行case 0,变量b没有进行初始化,但是由于在case 0部分b是不可见的,因此不会对程序造成任何影响,而如果执行default分支,则b会被初始化,因此程序没有报错。

  归根到底,出现上述的crosses initialization和jump to case label错误的原因是由于变量的作用域问题,因此一个好的习惯就是在case子句下面加上大括号来限定变量的作用域。

 switch(a)
{
case : {int b=;cout<<b<<endl;break;}
case : break;
default: break;
}

  不过要注意,一旦加上了大括号,在case 0后面便不能访问到变量b了。

  注意,如果上述代码以C方式进行编译,编译结果则会有所不同:

  main.c

#include <stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
int a =;
switch(a)
{ case : int b=;printf("%d\n",b);break;
case : break;
default:printf("%d\n",b);break;
}
return ;
}

  编译结果:

  报的错误意思是在该标签下不能定义变量。为什么呢?原因很简单,在C语言中所有的变量定义都必须放到所在语句块的最前面。所以如果改成这样:

#include <stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
int a =;
switch(a)
{
int b=;
case : printf("%d\n",b);break;
case : break;
default:printf("%d\n",b);break;
}
return ;
}

  编译结果:

  没有报错,注意这里没有报crosses initialization的错误,这点C和C++有点不同。如果以C++方式编译,肯定会报crosses initialization的错误,这也更加说明C++在语法方面要求比C更加严格。

  该程序运行的结果:

  输出32,是一个随机值。因为b并没有进行初始化,所以输出的是随机值。

  以上只是个人观点,若有不正之处,恳请指正,以免误导他人。

浅析C/C++中的switch/case陷阱的更多相关文章

  1. java中的Switch case语句

    java中的Switch case 语句 在Switch语句中有4个关键字:switch,case break,default. 在switch(变量),变量只能是整型或者字符型,程序先读出这个变量的 ...

  2. java中的switch case

    switch-case语句格式如下 switch(变量){ case 变量值1: //; break; case 变量值2: //...; break; ... case default: //... ...

  3. C#中的switch case

    在C#中switch(type){case tpye1:break;case tpye2:break;case tpye3:break;case tpye4:break;};其中type可以是数字,也 ...

  4. C#中,switch case语句中多个值匹配一个代码块的写法

    switch (num) { case 1: Response.Write("1"); break; case 2: case 3: Response.Write("2| ...

  5. java中的switch case default break

    package com.didispace; /** * Created by gmq on 2017/08/07. * * @version 1.0 * @since 2017/08/07 10:4 ...

  6. JS中的switch case

    function GetDepartmentName(type) { switch (type) { case DepartMentQian: alert($('#DepartMentQian').v ...

  7. Java中的Switch....case语句:

    一.格式: switch(表达式){ case 常量表达式1:  语句1;    case 常量表达式2:  语句2;    …     case 常量表达式n:  语句n;    default: ...

  8. react jsx 中使用 switch case 示例

    <div> <span>适用平台:</span> <span>{(() => { switch (currentItems.usePlatform ...

  9. JSX中写 switch case 进行判断

    场景:根据后端返回的数据进行多条件渲染,三元表达式已不能满足条件. 代码: <span> {(() => { switch (record.generalRuleInfos[0]?. ...

随机推荐

  1. [转]MySQL 清空慢查询文件

    概述 本章主要写当慢查询文件很大的时候怎样在线生成一个新的慢查询文件. 测试环境:mysql 5.6.21 步骤 配置慢查询 默认的my.cnf文件在/etc/目录下 vim /etc/my.cnf ...

  2. salesforce零基础学习(九十二)使用Ant Migration Tool 实现Metadata迁移

    我们在做项目时经常会使用changeset作为部署工具,但是某些场景使用changeset会比较难操作,比如当我们在sandbox将apex class更改名字想要部署到生产的org或者其他环境的or ...

  3. python args kwargs 传递参数的区别

    先来看个例子: def foo(*args, **kwargs): print 'args = ', args print 'kwargs = ', kwargs print '----------- ...

  4. vue-14-less 语法的使用

    vue-15-rem-less 在计算手机端页面的时候, 使用rem和less的方式, 可以方便的设置需要的大小等 1, 在index.html中添加rem的script 代码 在head中添加 &l ...

  5. java for循环里面执行sql语句操作,有效结果只有一次,只执行了一次sql mybatis 循环执行update生效一次 实际只执行一次

    java后台controller中,for循环执行数据库操作,但是发现实际仅仅执行了一次,或者说提交成功了一次,并没有实际的个数循环 有可能是同一个对象导致的 可以仔细看一下下面两段代码有什么区别 p ...

  6. Mysql加锁过程详解(5)-innodb 多版本并发控制原理详解

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  7. python面向对象入门(1):从代码复用开始

    本文从代码复用的角度一步一步演示如何从python普通代码进化到面向对象,并通过代码去解释一些面向对象的理论.所以,本文前面的内容都是非面向对象的语法实现方式,只有在最结尾才给出了面向对象的简单语法介 ...

  8. 基于SpringMVC+Spring+MyBatis实现秒杀系统【概况】

    前言 本教程使用SpringMVC+Spring+MyBatis+MySQL实现一个秒杀系统.教程素材来自慕课网视频教程[https://www.imooc.com/learn/631].有感兴趣的可 ...

  9. vsphere 虚拟机的迁移,冷迁移,vmotion(热迁移)

    备注:(理论部分参考王春海老师的课程) 一.概述 1.vsphere数据中心当处于某种目的进行维护时,需要将某台主机上运行或关闭的虚拟机,迁移到其他主机上,这个时候就需要使用迁移 2.可以使用冷迁移或 ...

  10. zepto的ready方法

    zepto中的ready函数是作为$.fn的一个方法,即作为一个zepto对象的方法 readyRE = /complete|loaded|interactive/; ready: function( ...