一、事情来源

  事情来源是一段奇怪的代码,代码如下

    int x = 1000;
switch (x) {
case 1000:
{
NSLog(@"%d", 1);
}
case 2000:
{
NSLog(@"%d", 2);
}
break;
case 3:
NSLog(@"%d", 3);
break;
default:
NSLog(@"%d", -1);
case 4:
NSLog(@"%d", 4);
break;
case 5:
NSLog(@"%d", 5);
break;
}

  当 x = 1000的时候,代码输出的是 1和2 ,也就是 1000 和 2000的case都执行了。(测试环境是Xcode + Mac iphone 模拟器)

  原因是什么?为什么不是和if else if else一样呢

  根据网上的资料,VC6.0的编译器在case数量小于3个的时候,会使用类似if else if else的语句,

  也就是这个case不加break语句的时候,进入下一条case的时候依然需要判断条件。

  当case数量较多的时候,编译器为了优化性能,会产生一个表,表的地址就是case的汇编入口,每个case完了之后下面接着是一个break语句,jump到switch case结束的地方

  如果你的case忘记了break语句,那么很可能继续执行到下一个case,因为所有case的指令都是平铺的,知道运行到break

  那么在iOS的设备上,不管你是几条指令,编译器都会使用跳转表的方式实现。

  比如下面的代码的汇编指令:

  

    int x = 1;
switch (x) {
case 1:
{
NSLog(@"%d", 1);
}
case 2:
{
NSLog(@"%d", 2);
}
case 3:
NSLog(@"%d", 3); case 4:
NSLog(@"%d", 4);
break;
case 5:
NSLog(@"%d", 5);
break;
default:
NSLog(@"%d", -1);
}

  

对应汇编

0x10da4361a <+58>:  movl   -0x24(%rbp), %eax
0x10da4361d <+61>: decl %eax
0x10da4361f <+63>: movl %eax, %esi
0x10da43621 <+65>: subl $0x4, %eax
0x10da43624 <+68>: movq %rsi, -0x30(%rbp)
0x10da43628 <+72>: movl %eax, -0x34(%rbp)
0x10da4362b <+75>: ja 0x10da436bd ; <+221> at ViewController.m
0x10da43631 <+81>: leaq 0xa4(%rip), %rax ; -[ViewController viewDidLoad] + 252
0x10da43638 <+88>: movq -0x30(%rbp), %rcx
0x10da4363c <+92>: movslq (%rax,%rcx,4), %rdx
0x10da43640 <+96>: addq %rax, %rdx
0x10da43643 <+99>: jmpq *%rdx
0x10da43645 <+101>: leaq 0x1a14(%rip), %rax ; @"%d"
0x10da4364c <+108>: movl $0x1, %esi
0x10da43651 <+113>: movq %rax, %rdi
0x10da43654 <+116>: movb $0x0, %al
0x10da43656 <+118>: callq 0x10da43a14 ; symbol stub for: NSLog
0x10da4365b <+123>: leaq 0x19fe(%rip), %rax ; @"%d"
0x10da43662 <+130>: movl $0x2, %esi
0x10da43667 <+135>: movq %rax, %rdi
0x10da4366a <+138>: movb $0x0, %al
0x10da4366c <+140>: callq 0x10da43a14 ; symbol stub for: NSLog
0x10da43671 <+145>: leaq 0x19e8(%rip), %rax ; @"%d"
0x10da43678 <+152>: movl $0x3, %esi
0x10da4367d <+157>: movq %rax, %rdi
0x10da43680 <+160>: movb $0x0, %al
0x10da43682 <+162>: callq 0x10da43a14 ; symbol stub for: NSLog
0x10da43687 <+167>: leaq 0x19d2(%rip), %rax ; @"%d"
0x10da4368e <+174>: movl $0x4, %esi
0x10da43693 <+179>: movq %rax, %rdi
0x10da43696 <+182>: movb $0x0, %al
0x10da43698 <+184>: callq 0x10da43a14 ; symbol stub for: NSLog
0x10da4369d <+189>: jmp 0x10da436d3 ; <+243> at ViewController.m:66
0x10da436a2 <+194>: leaq 0x19b7(%rip), %rax ; @"%d"
0x10da436a9 <+201>: movl $0x5, %esi
0x10da436ae <+206>: movq %rax, %rdi
0x10da436b1 <+209>: movb $0x0, %al
0x10da436b3 <+211>: callq 0x10da43a14 ; symbol stub for: NSLog
0x10da436b8 <+216>: jmp 0x10da436d3 ; <+243> at ViewController.m:66
0x10da436bd <+221>: leaq 0x199c(%rip), %rax ; @"%d"
0x10da436c4 <+228>: movl $0xffffffff, %esi ; imm = 0xFFFFFFFF
0x10da436c9 <+233>: movq %rax, %rdi
0x10da436cc <+236>: movb $0x0, %al
0x10da436ce <+238>: callq 0x10da43a14 ; symbol stub for: NSLog

  

  可以看到输出1,2,3 的case下面都没jmp指令;case 4的时候,会出现jump指令,也就是上面的代码是采用跳转表进行优化的。

  回到最开始的代码,如果如数的x = 30的时候,会输出多少呢?

  

    int x = 1000;
switch (x) {
case 1000:
{
NSLog(@"%d", 1);
}
case 2000:
{
NSLog(@"%d", 2);
}
break;
case 3:
NSLog(@"%d", 3);
break;
default:
NSLog(@"%d", -1);
case 4:
NSLog(@"%d", 4);
break;
case 5:
NSLog(@"%d", 5);
break;
}

  会走到default分支,输出-1;然后走到下面4的case,输出4.

  

  

  

switch case 跳转表的更多相关文章

  1. switch...case 和 if...else

    switch...case与if...else的根本区别在于: switch...case会生成一个跳转表来指示实际的case分支的地址,而这个跳转表的索引号与switch变量的值是相等的,switc ...

  2. javascript switch..... case

    switch(条件表达式) { case 常量: { 语句a; } break; case 常量: { 语句b; } break; case 常量: { 语句c; } break; ... case ...

  3. switch...case...语句分析(大表跟小表何时产生)

    一.switch...case...的格式 switch(表达式) { case 常量表达式1: 语句; break; case 常量表达式2: 语句; break; case 常量表达式3: 语句; ...

  4. 为什么说在使用多条件判断时switch case语句比if语句效率高?

    在学习JavaScript中的if控制语句和switch控制语句的时候,提到了使用多条件判断时switch case语句比if语句效率高,但是身为小白的我并没有在代码中看出有什么不同.去度娘找了半个小 ...

  5. if语句,if...else if语句和switch...case语句的区别和分析

    前段时间在工作中遇到了一个关于条件判断语句的问题,在if语句,if else if语句和switch case语句这三者之间分析,使用其中最有效率的一种方法. 所以就将这个问题作为自己第一篇博客的主要 ...

  6. 为什么switch...case语句比if...else执行效率高

    在C语言中,教科书告诉我们switch...case...语句比if...else if...else执行效率要高,但这到底是为什么呢?本文尝试从汇编的角度予以分析并揭晓其中的奥秘. 第一步,写一个d ...

  7. C语言switch/case圈复杂度优化重构

    软件重构是改善代码可读性.可扩展性.可维护性等目的的常见技术手段.圈复杂度作为一项软件质量度量指标,能从一定程度上反映这些内部质量需求(当然并不是全部),所以圈复杂度往往被很多项目采用作为软件质量的度 ...

  8. if else if,switch case二者的联系与区别

    前段时间在学习中听到了一个关于条件判断语句的问题,分析if else if语句和switch case语句这两者之间的联系和区别,从而使用其中最有效率的一种方法. 一.if...else if if. ...

  9. 知识扩展--if...else...与switch...case...的执行原理

    一.简述 编程语言中的条件分支结构有两种:if-else和switch-case,这两种条件分支之间可以相互转换,但是也存在一些区别,那么什么时候该用if-else,什么时候该用switch-case ...

  10. if else和switch case那个效率更高一点

    switch...case写法: switch (表达式){ case 值1 : 语句1 break; case 值2 : 语句2 break; ... default : 语句n break; } ...

随机推荐

  1. https http2 http3

    HTTP 1.1 对比 1.0,HTTP 1.1 主要区别主要体现在: 缓存处理:在 HTTP 1.0 中主要使用 header 里的 If-Modified-Since,Expires 来做为缓存判 ...

  2. 用了那么久的Lombok,你知道它的原理么?

    简介: 在写Java代码的时候,最烦写setter/getter方法,自从有了Lombok插件不用再写那些方法之后,感觉再也回不去了,那你们是否好奇过Lombok是怎么把setter/getter方法 ...

  3. 如何 0 改造,让单体/微服务应用成为 Serverless Application

    简介: 随着 2013 年以 Docker 为代表的容器技术.CNCF 基金会以及 K8s 的发展等,云原生开始被广大开发者所熟知.云原生时代之前还有两个阶段:一是自建 IDC 机房,二是简单地把原有 ...

  4. 所有前端都要看的2D游戏化互动入门基础知识

    简介: 在非游戏环境中将游戏的思维和游戏的机制进行整合运用,以引导用户互动和使用 本文作者:淘系前端团队-Eva.js作者-明非 背景 现在越来越多的公司和 App 开始使用游戏化的方式去做产品了,所 ...

  5. 数据库误操作后悔药来了:AnalyticDB PostgreSQL教你实现分布式一致性备份恢复

    ​简介: 本文将介绍AnalyticDB PostgreSQL版备份恢复的原理与使用方法. 一.背景 AnalyticDB PostgreSQL版(简称ADB PG)是阿里云数据库团队基于Postgr ...

  6. 阿里云CDN操控2.0版本正式发布

    ​简介: 2021年8月,阿里云边缘云CDN完成过去3年来最大的一次版本升级. 2021年8月,阿里云边缘云CDN完成过去3年来最大的一次版本升级.本次升级根据上万企业客户的使用反馈和行业应用特征,从 ...

  7. 【学习笔记】Python 使用 matplotlib 画图

    目录 安装 中文显示 折线图.点线图 柱状图.堆积柱状图 坐标轴断点 参考资料 本文将介绍如何使用 Python 的 matplotlib 库画图,记录一些常用的画图 demo 代码 安装 # 建议先 ...

  8. HAL库移植RT-Thread Nano

    一.移植RT-Thread Nano准备 keil软件 CubeMx软件 STM32 CubeMx使用教程:https://www.cnblogs.com/jzcn/p/16313803.html S ...

  9. 009_原理图中电气互连,Net alias,分页符,总线

    009_原理图中电气互连,Net alias,分页符,总线 1.电气互连,就是画线. 2.端口名,适用同一页相连的端口. 3.分页符off page connector,适用于不同页的端口连接. 4. ...

  10. Codeforces Good Bye 2023

    A. 2023 正常签到. void solve() { int n, k, ok = 1; cin >> n >> k; int t = 2023; while(n --) ...