马振邦徒弟:gcc对c语言中的switch的优化

来源:百度文库 编辑:九乡新闻网 时间:2024/04/28 18:20:03
在c语言中switch语句会被实现为一个跳转表,跳转表是一个数组,这个数组里面存的都是地址,也就是说只要你传递给它一个i,他就会返回给你,你所需要跳转的地址,这样做得好处就是执行语句的时间和条件的个数无关..不过在gcc里面他也只是条件数大于4个,才会生成这个跳转表.

请看下面的代码:
Java代码  
  1. int switch_eg(int x)    
  2. {    
  3.     int result = x;    
  4.   
  5.     switch (x) {    
  6.   
  7.     case 100:    
  8.     result *= 13;    
  9.     break;    
  10.   
  11.     case 102:    
  12.     result += 10;    
  13.     /* Fall through */    
  14.   
  15.     case 103:    
  16.     result += 11;    
  17.     break;    
  18.   
  19.     case 104:    
  20.     case 106:    
  21.     result *= result;    
  22.     break;    
  23.   
  24.     default:    
  25.     result = 0;          
  26.     }    
  27.   
  28.     return result;    
  29. }   

这只是一段简单的switch语句,下面我们用一段c代码来描述汇编代码所要做得事情.
Java代码  
  1. code *jt[7] = {   
  2.     loc_A, loc_def, loc_B, loc_C,     
  3.     loc_D, loc_def, loc_D   
  4. };    
  5.     
  6. int switch_eg_impl(int x)    
  7. {    
  8.     unsigned xi = x - 100;    
  9.     int result = x;    
  10.   
  11.     if (xi > 6)    
  12.     goto loc_def;    
  13.   
  14.     /* Next goto is not legal C */    
  15.     goto jt[xi];    
  16.   
  17.  loc_A:      /* Case 100 */    
  18.     result *= 13;    
  19.     goto done;    
  20.   
  21.  loc_B:      /* Case 102 */    
  22.     result += 10;    
  23.     /* Fall through */    
  24.        
  25.  loc_C:    /* Case 103 */    
  26.     result += 11;    
  27.     goto done;    
  28.   
  29.  loc_D:    /* Cases 104, 106 */    
  30.     result *= result;    
  31.     goto done;    
  32.   
  33.  loc_def:  /* Default case*/    
  34.     result = 0;    
  35.   
  36.  done:    
  37.     return result;    
  38. }   

看上面的代码就很清楚了,它会对传进来的值与100进行一个减法,然后再将这个值传进switch语句.
而真实的汇编代码是怎么样的呢,我们可以看看:
Java代码  
  1. switch_eg:   
  2.     pushl   %ebp   
  3.     movl    %esp, %ebp   
  4.     movl    8(%ebp), %eax   //这边得到传进来的参数   
  5.     leal    -100(%eax), %edx //这边将得到的参数和100做差   
  6.     cmpl    $6, %edx //这边和6比较,如果大于6说明下面的条件没有满足的所以默认进入default   
  7.     jbe .L11   
  8. .L2:   
  9.     popl    %ebp   
  10.     xorl    %eax, %eax   
  11.     ret   
  12.     .p2align 4,,7  
  13. .L11:   
  14.     jmp *.L7(,%edx,4)       //这边也就是我们上面伪码所描述的那个jt[xi]   
  15.     .section    .rodata   
  16.     .align 4  
  17.     .align 4  
  18. .L7:                    //这边就是所构造的跳转表.   
  19.     .long   .L3   
  20.     .long   .L2   
  21.     .long   .L4   
  22.     .long   .L5   
  23.     .long   .L6   
  24.     .long   .L2   
  25.     .long   .L6   
  26.     .text   
  27. .L6:                         // loc_D   
  28.     imull   %eax, %eax     
  29.     popl    %ebp   
  30.     .p2align 4,,6  
  31.     ret   
  32. .L5:                             //loc_c   
  33.     popl    %ebp   
  34.     movl    $114, %eax   
  35.     .p2align 4,,6  
  36.     ret   
  37. .L4:                          //loc_B   
  38.     popl    %ebp   
  39.     movl    $123, %eax   
  40.     .p2align 4,,4  
  41.     ret   
  42. .L3:                          //loc_A   
  43.     popl    %ebp   
  44.     movl    $1300, %eax   
  45.     .p2align 4,,4  
  46.     ret