C语言汇编代码分析(switch case)

我们来看下面的例子:




 
 switch-case控制语句维护着一张跳转表(jump table),并不是用一系列的if-else来实现,在上例中就是标签L7标

记的地方。

跳转表方式大体思想是这样的:

用case语句中的最大值减去最小值求出一个区间,这里是106-100 = 6,即 0到6共有7个可能的case,此时编译器

为该switch-case控制分配长度为7的数组,然后编译器再去查询哪些case是出现了的,就在数组中对应位置填上该

case的地址(即L3,L4,L9,L6),如果没有对应的case就填写default对应的地址(即L2)。最后在执行的时候,只要

用switch的参数(即n)减去case中的最小值,就可以得到一个索引,用这个索引就可以直接跳转到对应的case语

句。这样比用if-else判断效率更高。

下面来具体分析下上面的汇编代码:

swithcase_asm:

pushl %ebp;函数管理用

movl %esp, %ebp;函数管理用

movl 8(%ebp), %eax;得到x

movl 12(%ebp), %edx;得到n

subl $100, %edx;用n-100存到%edx中

cmpl $6, %edx;比较%edx 与 6

ja .L2;如果%edx的值比6大则直接跳转到标签L2,即default

jmp *.L7(,%edx,4);如果小于等于6,在索引表中查找后跳转到对应的case

.section .rodata

.align 4

.align 4

.L7:                                            ;跳转表

.long .L3

.long .L2

.long .L4

.long .L9

.long .L6

.long .L2

.long .L6

.text

.L2:                                            ;default

movl $0, %eax

jmp .L8

.L3:                                            ;case 100

leal (%eax,%eax,2), %edx

leal (%eax,%edx,4), %eax

jmp .L8

.L4:                                           ;case 102

addl $10, %eax

.L9:                                           ;case 103

addl $11, %eax

jmp .L8

.L6:                                          ;case 104,106

imull %eax, %eax

.L8:

popl %ebp

ret

但是如果都采用跳转表的方式会有一个问题,那就内存消耗,如果case语句中最大值和最小值相差较大,

那么会消耗掉大量的内存,接下来我们来看编译器在这种情况下是如何处理的:

 


 
 

 

 我们将case 106改为case 1106,我们再看汇编代码,已经没有了跳转表的踪影了,没错,你猜对了,这种情况下编译器还是用了if-else控制方式。不过也用二分查找进行了优化(上面红色矩形框住的区域)。

那么通过上面的汇编分析,我们可以看出,在编写switch-case结构的时候,为了使程序运行更快,应该避免使用区间差距

太大的数。

猜你喜欢

转载自becomebetter.iteye.com/blog/2205785