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; } ...
随机推荐
- 重新点亮shell————sed的替换[十]
前言 简单介绍一下sed 和 awk. 正文 这两个和vim的区别: vim 是交互式和 他们是非交互式 vim是文件操作模式与他们是行交互模式 sed sed 的 模式空间. sed的基本工作方式是 ...
- sql 语句系列(记录时间差)[八百章之第十八章]
计算当前记录和下一条记录之间的日期差 关键点在于如何获得下一条日期. mysql 和 sql server select x.*,DATEDIFF(day,x.HIREDATE,x.next_hd) ...
- kolla-ansible部署OpenStack Train版技术方案
简单架构示意 项目目标 1. 实现容器化部署docker+ Ansible+openstack-tarin 2. 使用keeplived监控nova服务实现在单台服务器宕机的情况下能迅速切断连接减轻平 ...
- cookie与localStorage与sessionStorage
1. cookie 1_1: 简述 HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送(由服务器设置后返回给浏览器端)到用户浏览器并保存在本地的一小块数据.浏览器 ...
- JVM简明笔记2:运行时数据区
1 内存布局总体结构 根据 JVM 规范,JVM 内存共分为虚拟机栈(Virtual Machine Stacks).堆(Heap).方法区(Method Area).程序计数器(Program Co ...
- 力扣283(java)-移动零(简单)
题目: 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 请注意 ,必须在不复制数组的情况下原地对数组进行操作. 示例 1: 输入: nums = [0, ...
- T级内存,创建效率提升10倍以上,阿里云 KVM异构虚拟机启动时间优化实践
简介: 阿里云工程师李伟男和郭成在 KVM Forum 2020 上详细介绍了阿里云 KVM 虚拟机创建及启动时间优化的具体技术实现,本文根据其演讲整理而成. 对于云计算用户来说,过长的 KVM 虚拟 ...
- EventBridge 集成云服务实践
简介:本篇文章主要向大家分享了通过 EventBridge 如何集成云产品事件源,如何集成云产品事件目标以及通过事件流如何集成消息产品. 作者:李凯(凯易) EvenBridge 集成概述 Even ...
- 一个开源轻量级的C#代码格式化工具(支持VS和VS Code)
前言 C#代码格式化工具除了ReSharper和CodeMaid,还有一款由.NET开源.免费(MIT License).轻量级的C#语言代码格式化工具:CSharpier. 工具介绍 CSharpi ...
- [ABC345D] Tiling 位运算の极致运用
[ABC345D] Tiling 原题解地址:Editorial by Kiri8128 神写法. 将 \(H \times W\) 的网格展开为 \(H \times (W + 1)\) 的序列, ...