这个问题,之前一直没有去思考,在c和指针这本书中,在谈到switch是给出了这样一段话:
也就是说switch的条件要是整型值?好像一直这么用,却没有研究过为什么。惭愧。。。
研究c语言最好就是看其汇编实现,下面在linux 64位上实验。
编译运行,输出10;
然后将目标文件dump出来
int main()
{
40052d: 55 push %rbp
40052e: 48 89 e5 mov %rsp,%rbp
400531: 48 83 ec 10 sub $0x10,%rsp
int a=10;
400535: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)
switch(a)
40053c: 8b 45 fc mov -0x4(%rbp),%eax
40053f: 83 f8 01 cmp $0x1,%eax
400542: 74 07 je 40054b <main+0x1e>
400544: 83 f8 0a cmp $0xa,%eax
400547: 74 0e je 400557 <main+0x2a>
400549: eb 18 jmp 400563 <main+0x36>
{
case 1:
printf("1\n");
40054b: bf 04 06 40 00 mov $0x400604,%edi
400550: e8 bb fe ff ff callq 400410 <puts@plt>
break;
400555: eb 17 jmp 40056e <main+0x41>
case 10:
printf("10\n");
400557: bf 06 06 40 00 mov $0x400606,%edi
40055c: e8 af fe ff ff callq 400410 <puts@plt>
break;
400561: eb 0b jmp 40056e <main+0x41>
default:
printf("default\n");
400563: bf 09 06 40 00 mov $0x400609,%edi
400568: e8 a3 fe ff ff callq 400410 <puts@plt>
break;
40056d: 90 nop
}
return 0;
40056e: b8 00 00 00 00 mov $0x0,%eax
}
主要看看这段代码,就是switch一句代码展开好多汇编代码
switch(a)
40053c: 8b 45 fc mov -0x4(%rbp),%eax
40053f: 83 f8 01 cmp $0x1,%eax
400542: 74 07 je 40054b <main+0x1e>
400544: 83 f8 0a cmp $0xa,%eax
400547: 74 0e je 400557 <main+0x2a>
400549: eb 18 jmp 400563 <main+0x36>
将a的值存放到寄存器eax中,然后出现两个比较三个挑战,就是下面的两个case 条件,
是否可以就此下结论,switch的实现如上所述,翻开深入理解计算机系统,有一节讲的switch,而上面说的是switch的实现是利用跳转表,而我的测试代码却没有。
抛开这个问题不谈,使用比较跳转这样的实现方式是不是有点效率偏低。如果有n多个case比较,那不是死定了。。。而深入计算机书中讲的的是一种查表法(好吧,这让我想起了FPGA芯片的实现方式)。
是不是gcc会根据case多少自己优化?
接下来将case加多,编写实验,将打印语句去掉。
然后dump出目标文件,如下
int main()
{
4004ed: 55 push %rbp
4004ee: 48 89 e5 mov %rsp,%rbp
int a=10;
4004f1: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)
switch(a)
4004f8: 8b 45 fc mov -0x4(%rbp),%eax
4004fb: 83 e8 0a sub $0xa,%eax
4004fe: 83 f8 07 cmp $0x7,%eax
400501: 77 0c ja 40050f <main+0x22>
400503: 89 c0 mov %eax,%eax
400505: 48 8b 04 c5 a8 05 40 mov 0x4005a8(,%rax,8),%rax
40050c: 00
40050d: ff e0 jmpq *%rax
case 16:
break;
case 17:
break;
default:
break;
40050f: 90 nop
400510: eb 01 jmp 400513 <main+0x26>
case 15:
break;
case 16:
break;
case 17:
break;
400512: 90 nop
default:
break;
}
return 0;
400513: b8 00 00 00 00 mov $0x0,%eax
}
令人发指的事情出现了。。看看这段代码
switch(a)
4004f8: 8b 45 fc mov -0x4(%rbp),%eax
4004fb: 83 e8 0a sub $0xa,%eax
4004fe: 83 f8 07 cmp $0x7,%eax
400501: 77 0c ja 40050f <main+0x22>
400503: 89 c0 mov %eax,%eax
400505: 48 8b 04 c5 a8 05 40 mov 0x4005a8(,%rax,8),%rax
40050c: 00
40050d: ff e0 jmpq *%rax
并没有出现依次比较跳转的实现方式。
f8处代码,将a的值存放到寄存器eax中
fb代码,将eax的值减去10;实际这是一种映射思想,
下面一个比较和跳转是判断eax的值超过7的,对应default的情况。
再下面的mov和jmpq就是重要的问题了。
看看这个汇编代码
mov 0x4005a8(,%rax,8),%rax
困了 明天再分析。。
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/u010442328/article/details/47818275