switch case 跳转表
一、事情来源
事情来源是一段奇怪的代码,代码如下
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 跳转表的更多相关文章
- switch...case 和 if...else
switch...case与if...else的根本区别在于: switch...case会生成一个跳转表来指示实际的case分支的地址,而这个跳转表的索引号与switch变量的值是相等的,switc ...
- javascript switch..... case
switch(条件表达式) { case 常量: { 语句a; } break; case 常量: { 语句b; } break; case 常量: { 语句c; } break; ... case ...
- switch...case...语句分析(大表跟小表何时产生)
一.switch...case...的格式 switch(表达式) { case 常量表达式1: 语句; break; case 常量表达式2: 语句; break; case 常量表达式3: 语句; ...
- 为什么说在使用多条件判断时switch case语句比if语句效率高?
在学习JavaScript中的if控制语句和switch控制语句的时候,提到了使用多条件判断时switch case语句比if语句效率高,但是身为小白的我并没有在代码中看出有什么不同.去度娘找了半个小 ...
- if语句,if...else if语句和switch...case语句的区别和分析
前段时间在工作中遇到了一个关于条件判断语句的问题,在if语句,if else if语句和switch case语句这三者之间分析,使用其中最有效率的一种方法. 所以就将这个问题作为自己第一篇博客的主要 ...
- 为什么switch...case语句比if...else执行效率高
在C语言中,教科书告诉我们switch...case...语句比if...else if...else执行效率要高,但这到底是为什么呢?本文尝试从汇编的角度予以分析并揭晓其中的奥秘. 第一步,写一个d ...
- C语言switch/case圈复杂度优化重构
软件重构是改善代码可读性.可扩展性.可维护性等目的的常见技术手段.圈复杂度作为一项软件质量度量指标,能从一定程度上反映这些内部质量需求(当然并不是全部),所以圈复杂度往往被很多项目采用作为软件质量的度 ...
- if else if,switch case二者的联系与区别
前段时间在学习中听到了一个关于条件判断语句的问题,分析if else if语句和switch case语句这两者之间的联系和区别,从而使用其中最有效率的一种方法. 一.if...else if if. ...
- 知识扩展--if...else...与switch...case...的执行原理
一.简述 编程语言中的条件分支结构有两种:if-else和switch-case,这两种条件分支之间可以相互转换,但是也存在一些区别,那么什么时候该用if-else,什么时候该用switch-case ...
- if else和switch case那个效率更高一点
switch...case写法: switch (表达式){ case 值1 : 语句1 break; case 值2 : 语句2 break; ... default : 语句n break; } ...
随机推荐
- leetcode:655. 输出二叉树
655. 输出二叉树 在一个 m*n 的二维字符串数组中输出二叉树,并遵守以下规则: 1> 行数 m 应当等于给定二叉树的高度. 2> 列数 n 应当总是奇数. 3> 根节点的值(以 ...
- leetcode:3. 无重复字符的最长子串
3. 无重复字符的最长子串 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子 ...
- Llama3-8B到底能不能打?实测对比
前几天Meta开源发布了新的Llama大语言模型:Llama-3系列,本次一共发布了两个版本:Llama-3-8B和Llama-3-70B,根据Meta发布的测评报告,Llama-3-8B的性能吊打之 ...
- 剑指offer29(Java)-顺时针打印矩阵(简单)
题目: 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字. 示例 1: 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]输出:[1,2,3,6,9,8,7,4,5 ...
- 力扣209(java&python)-长度最小的子数组(中等)
题目: 给定一个含有 n 个正整数的数组和一个正整数 target . 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, ...
- 通过定时SQL提取阿里云API网关访问日志指标
简介: 阿里云API网关服务提供API托管服务,提供了强大的适配和集成能力,可以将各种不同的业务系统API实现统一管理.API网关同时支持将API访问日志一键存储到日志服务,通过日志服务强大的查询分析 ...
- 五分钟学会使用 go modules(含在家办公使用技巧)
导读:go modules 是 golang 1.11 新加的特性.如今 1.13 都已经发布了第 7 个小版本了,几乎所有大项目均已开始使用,这自然也包括 Kubernetes 生态中的众多项目.笔 ...
- 码住!Flink Contributor 速成指南
简介: 不管初衷是什么,Flink 都非常欢迎大家一起建设和完善社区.在开始具体的贡献步骤之前,我们先简要介绍一下参与贡献的几种途径,以及 Clarify 关于开源贡献的一些固有印象. 作者:伍翀(云 ...
- dotnet 7 已知问题 WPF 的 TreeView 开启虚拟化之后只显示首项
本文记录 WPF 在 dotnet 7 的一个已知问题,此问题当前已修复,只需更新 SDK 或运行时即可.使用 TreeView 在开启虚拟化之后只显示首项,其他项不显示.本文将告诉大家此问题的原因和 ...
- Linux系统命令-目录命令
1.ls命令:主要作用是显示目录下的内容 基本格式 [root@localhost ~]# ls [选项] [参数是文件名或目录名] 常用选项 -a:显示所有文件 --color=when:支持颜色输 ...