一、事情来源

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

    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. android 找不到设备

    前言 当我们安装android studio的时候,测试的时候,你可能找不到设备. 我遇到的有两种情况,一种是本身就需要安装插件,如一些低端机或者有些小米机. 还有一种情况需要去触发一下,有些华为手机 ...

  2. js es6 map weakmap

    前言 这里介绍一些map和weakmap的一些属性和他们不同之处. 正文 map JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键.这 ...

  3. 实训篇-Html-多媒体标签

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  4. Causal Inference理论学习篇-Tree Based-Causal Forest

    广义随机森林 了解causal forest之前,需要先了解其forest实现的载体:GENERALIZED RANDOM FORESTS[6](GRF) 其是随机森林的一种推广, 经典的随机森林只能 ...

  5. 力扣383(java&python)-赎金信(简单)

    题目: 给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成. 如果可以,返回 true :否则返回 false . m ...

  6. 一款跑在云上的定制容器专属 OS 来了——LifseaOS | 龙蜥技术

    ​简介:如果可以把运维 API 化,那我们是不是可以把 OS 也作为一个 K8S 可以管理的资源,让 K8S 像管理容器一样管理OS? ​ 引言 在 2021 年 10 月的云栖大会上,为云原生而生的 ...

  7. 10个Bug环环相扣,你能解开几个?

    ​简介:由阿里云云效主办的2021年第3届83行代码挑战赛已经收官.超2万人围观,近4000人参赛,85个团队组团来战.大赛采用游戏闯关玩儿法,融合元宇宙科幻和剧本杀元素,让一众开发者玩得不亦乐乎. ...

  8. VisualStudio 禁用移动文件到文件夹自动修改命名空间功能

    在 VisualStudio 2022 里的某个版本开始,将会在移动文件到其他文件夹时,自动修改命名空间,使用匹配文件夹路径的命名空间.如果这个功能能顺手将其他引用此类型的全部符号同时变更,那自然是很 ...

  9. LVGL 定时器

    LVGL 8.0 以后好像取消了自定义任务模块,想要使用多线程只能使用系统的线程. 一.定时器结构体 typedef struct _lv_timer_t { uint32_t period; // ...

  10. 局域网内一部分网络设备无法ping通,icmp_seq=1 目标主机不可达

    问题: 来自 192.168.2.99 icmp_seq=1 目标主机不可达.   最近想在局域网内搭建一台服务器,打开SSH服务后发现局域网内的一部分设备无法使用,尝试了各种办法都没能解决,重装系统 ...