• 汇编的角度分析C语言的switch语句


    1、Switch语句与if  else的关系:正向开发时,switch 几乎就是If else语句的另一种表达方式。

     

    if(表达式 == 常量1)            
    {            
        //...代码        
    }            
    else if(表达式 == 常量2)            
    {            
        //...代码        
    }            
    else if(表达式 == 常量3)            
    {            
        //...代码        
    }            
    else            
    {            
        //...代码        
    }            
                
                
    switch(表达式)        
        {        
                 case 常量表达式1:    
                语句;
                break;
            case 常量表达式2:    
                语句;
                break;
            case 常量表达式3:    
                语句;
                break;
            case 常量表达式3:    
                语句;
                break;
            default:    
                语句;
                break;
        }        

      switch要求:

      a、case后面必须是常量表达式

      b、case后常量表达式的值不能一样

      c、switch后面表达式必须为整数

    2、Switch中,case分支语句小于等于3时候,编译器在执行时候与if else一模一样,大于3的时候。开始生成大表结构

      源码:

    void fun(int x){            
        switch(x)            
        {            
            case 1:        
                printf("%d",1);    
                break;    
            case 2:        
                printf("%d",2);    
                break;    
            case 3:        
                printf("%d",3);        
                break;    
            /*case 4:            
                printf("%d",4);    
                break;    
            case 5:    
                printf("%d",5);    
                break;
            case 6:    
                printf("%d",6);    
                break;
                */
            default:        
                printf("%s","default");
                break;    
        }            
    
    }
    
    int main(int argc, char* argv[])
    {
        fun(3);
        return 0;
    }

      反汇编:

    00401020   push        ebp
    00401021   mov         ebp,esp
    00401023   sub         esp,44h
    00401026   push        ebx
    00401027   push        esi
    00401028   push        edi
    00401029   lea         edi,[ebp-44h]
    0040102C   mov         ecx,11h
    00401031   mov         eax,0CCCCCCCCh
    00401036   rep stos    dword ptr [edi]
    00401038   mov         eax,dword ptr [ebp+8]
    0040103B   mov         dword ptr [ebp-4],eax
    0040103E   cmp         dword ptr [ebp-4],1
    00401042   je          fun+32h (00401052) 
    00401044   cmp         dword ptr [ebp-4],2
    00401048   je          fun+43h (00401063)                     相等则跳转,分支跳转语句,和if else跳转几乎一致
    0040104A   cmp         dword ptr [ebp-4],3
    0040104E   je          fun+54h (00401074) 
    00401050   jmp         fun+65h (00401085) 
    00401052   push        1
    00401054   push        offset string "%d" (0042202c)
    00401059   call        printf (00401180)
    0040105E   add         esp,8
    00401061   jmp         fun+77h (00401097)
    00401063   push        2
    00401065   push        offset string "%d" (0042202c)
    0040106A   call        printf (00401180)
    0040106F   add         esp,8
    00401072   jmp         fun+77h (00401097)
    00401074   push        3
    00401076   push        offset string "%d" (0042202c)
    0040107B   call        printf (00401180)
    00401080   add         esp,8
    00401083   jmp         fun+77h (00401097)
    00401085   push        offset string "default" (00422020)
    0040108A   push        offset string "%s" (0042201c)
    0040108F   call        printf (00401180)
    00401094   add         esp,8
    00401097   pop         edi
    00401098   pop         esi
    00401099   pop         ebx
    0040109A   add         esp,44h
    0040109D   cmp         ebp,esp
    0040109F   call        __chkesp (00401200)
    004010A4   mov         esp,ebp
    004010A6   pop         ebp
    004010A7   ret

    分支语句大于3的

    源码:

    void fun(int x){            
        switch(x)            
        {            
            case 1:        
                printf("%d",1);    
                break;    
            case 2:        
                printf("%d",2);    
                break;    
            case 3:        
                printf("%d",3);        
                break;    
            case 4:            
                printf("%d",4);    
                break;    
            case 5:    
                printf("%d",5);    
                break;
            case 6:    
                printf("%d",6);    
                break;
                
            default:        
                printf("%s","default");
                break;    
        }            
    
    }
    
    int main(int argc, char* argv[])
    {
        fun(3);
        return 0;
    }

    反汇编:

    00401020   push        ebp
    00401021   mov         ebp,esp
    00401023   sub         esp,44h
    00401026   push        ebx
    00401027   push        esi
    00401028   push        edi
    00401029   lea         edi,[ebp-44h]
    0040102C   mov         ecx,11h
    00401031   mov         eax,0CCCCCCCCh
    00401036   rep stos    dword ptr [edi]
    00401038   mov         eax,dword ptr [ebp+8]
    0040103B   mov         dword ptr [ebp-4],eax
    0040103E   mov         ecx,dword ptr [ebp-4]           传入的参数 -1  放入第一个局部变量中    3-1=2   
    00401041 sub ecx,1 00401044 mov dword ptr [ebp-4],ecx
    00401047 cmp dword ptr [ebp-4],5 0040104B ja $L539+11h (004010bd) 跳入default 0040104D mov edx,dword ptr [ebp-4] 00401050 jmp dword ptr [edx*4+4010E0h] 查表直接跳转到分支语句,因此它的效率是最高的 $L533: 00401057 push 1 00401059 push offset string "%d" (0042202c) 0040105E call printf (00401180) 00401063 add esp,8 00401066 jmp $L539+23h (004010cf) $L535: 00401068 push 2 0040106A push offset string "%d" (0042202c) 0040106F call printf (00401180) 00401074 add esp,8 00401077 jmp $L539+23h (004010cf) $L536: 00401079 push 3 0040107B push offset string "%d" (0042202c) 00401080 call printf (00401180) 00401085 add esp,8 00401088 jmp $L539+23h (004010cf) $L537: 0040108A push 4 0040108C push offset string "%d" (0042202c) 00401091 call printf (00401180) 00401096 add esp,8 00401099 jmp $L539+23h (004010cf) $L538: 0040109B push 5 0040109D push offset string "%d" (0042202c) 004010A2 call printf (00401180) 004010A7 add esp,8 004010AA jmp $L539+23h (004010cf) $L539: 004010AC push 6 004010AE push offset string "%d" (0042202c) 004010B3 call printf (00401180) 004010B8 add esp,8 004010BB jmp $L539+23h (004010cf) 004010BD push offset string "default" (00422020) 004010C2 push offset string "%s" (0042201c) 004010C7 call printf (00401180) 004010CC add esp,8 004010CF pop edi 004010D0 pop esi 004010D1 pop ebx 004010D2 add esp,44h 004010D5 cmp ebp,esp 004010D7 call __chkesp (00401200) 004010DC mov esp,ebp 004010DE pop ebp 004010DF ret

       总结:

      生成大表直接查表的跳转,分支语句需要大于3,

      生成的大表

    3、既生成大表也生成小表的情况

      源码:

    void fun(int x){            
        switch(x)            
        {            
            case 1:        
                printf("%d",1);    
                
            case 8:    
                printf("%d",8);    
                break;
            case 9:    
                printf("%d",9);    
                break;
            case 10:    
                printf("%d",10);    
                break;
    
    
                
            default:        
                printf("%s","default");
                break;    
        }            
    
    }
    
    int main(int argc, char* argv[])
    {
        fun(9);
        return 0;
    }

      反汇编:

    00401020   push        ebp
    00401021   mov         ebp,esp
    00401023   sub         esp,44h
    00401026   push        ebx
    00401027   push        esi
    00401028   push        edi
    00401029   lea         edi,[ebp-44h]
    0040102C   mov         ecx,11h
    00401031   mov         eax,0CCCCCCCCh
    00401036   rep stos    dword ptr [edi]
    00401038   mov         eax,dword ptr [ebp+8]
    0040103B   mov         dword ptr [ebp-4],eax
    0040103E   mov         ecx,dword ptr [ebp-4]
    00401041   sub         ecx,1
    00401044   mov         dword ptr [ebp-4],ecx
    00401047   cmp         dword ptr [ebp-4],9
    0040104B   ja          $L537+11h (004010a1)
    0040104D   mov         eax,dword ptr [ebp-4]
    00401050   xor         edx,edx
    00401052   mov         dl,byte ptr  (004010d8)[eax]                  地址  004010d8+eax处的值
    00401058   jmp         dword ptr [edx*4+4010C4h]          4010c4  大表的地址,下边跟着很多小表的地址
    $L533:
    0040105F   push        1
    00401061   push        offset string "%d" (0042202c)
    00401066   call        printf (004011b0)
    0040106B   add         esp,8
    $L535:
    0040106E   push        8
    00401070   push        offset string "%d" (0042202c)
    00401075   call        printf (004011b0)
    0040107A   add         esp,8
    0040107D   jmp         $L537+23h (004010b3)
    $L536:
    0040107F   push        9
    00401081   push        offset string "%d" (0042202c)
    00401086   call        printf (004011b0)
    0040108B   add         esp,8
    0040108E   jmp         $L537+23h (004010b3)
    $L537:
    00401090   push        0Ah
    00401092   push        offset string "%d" (0042202c)
    00401097   call        printf (004011b0)
    0040109C   add         esp,8
    0040109F   jmp         $L537+23h (004010b3)
    004010A1   push        offset string "default" (00422020)
    004010A6   push        offset string "%s" (0042201c)
    004010AB   call        printf (004011b0)
    004010B0   add         esp,8
    004010B3   pop         edi
    004010B4   pop         esi
    004010B5   pop         ebx
    004010B6   add         esp,44h
    004010B9   cmp         ebp,esp
    004010BB   call        __chkesp (00401230)
    004010C0   mov         esp,ebp
    004010C2   pop         ebp
    004010C3   ret

      总结:大表是连续的地址储存的是分支跳转的地址

         中间隔开的值比较小的话,大表填充的是default的地址

         中间隔开比较大的时候,会生成小表,查小表来跳转

  • 相关阅读:
    NET下RabbitMQ实践[WCF发布篇]
    基于Mongodb分布式存储物理文件
    NET下RabbitMQ实践[实战篇]
    关于Memcache mutex设计模式的.net实现
    使用ServiceStackRedis链接Redis简介
    NET下RabbitMQ实践[示例篇]
    基于MongoDB分布式存储进行MapReduce并行查询
    Asp.Net开发小技巧汇总
    愈敏洪讲座
    图标下载利器
  • 原文地址:https://www.cnblogs.com/heyhx/p/14226754.html
Copyright © 2020-2023  润新知