码迷,mamicode.com
首页 > 其他好文 > 详细

研究研究看似简单的switch问题

时间:2015-08-21 00:13:45      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:switch   c语言   

这个问题,之前一直没有去思考,在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
困了 明天再分析。。

版权声明:本文为博主原创文章,未经博主允许不得转载。

研究研究看似简单的switch问题

标签:switch   c语言   

原文地址:http://blog.csdn.net/u010442328/article/details/47818275

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!