zoukankan      html  css  js  c++  java
  • switch...case...语句分析(大表跟小表何时产生)

    一、switch...case...的格式

     1     switch(表达式)            
     2     {            
     3         case 常量表达式1:        
     4             语句;    
     5             break;    
     6         case 常量表达式2:        
     7             语句;    
     8             break;    
     9         case 常量表达式3:        
    10             语句;    
    11             break;    
    12         case 常量表达式3:        
    13             语句;    
    14             break;    
    15         default:        
    16         语句;    
    17         break;    
    18     }

      switch要求:

      1、case后面必须是常量表达式
      2、case后常量表达式的值不能一样
      3、switch后面表达式必须为整数,不能为浮点数

      4、case后的语句可以有多个且不用花括号括起来;

      5、case和default子句的先后顺序可以先后变动,default子句可以省略不用;

    二、switch...case...与if...else...的区别

      1、switch语句 是if语句的简写,我们可以看一下分析,

     1 void Function(int m)
     2 {
     3     if (m == 1)
     4     {
     5         printf("%d
    ", 1);
     6     }
     7     else if (m == 2)
     8     {
     9         printf("%d
    ", 2);
    10     }
    11     else if (m == 3)
    12     {
    13         printf("%d
    ", 3);
    14     }
    15     else if (m == 4)
    16     {
    17         printf("%d
    ", 4);
    18     }
    19     else if (m == 5)
    20     {
    21         printf("%d
    ", 5);
    22     }    
    23 }
    24 
    25 int main(int argc, char* argv[])
    26 {
    27     Function(3);
    28     return 0;
    29 }

      反汇编代码如下

     1 00401020   push        ebp
     2 00401021   mov         ebp,esp
     3 00401023   sub         esp,40h
     4 00401026   push        ebx
     5 00401027   push        esi
     6 00401028   push        edi
     7 00401029   lea         edi,[ebp-40h]
     8 0040102C   mov         ecx,10h
     9 00401031   mov         eax,0CCCCCCCCh
    10 00401036   rep stos    dword ptr [edi]
    11 00401038   cmp         dword ptr [ebp+8],1
    12 0040103C   jne         Function+2Fh (0040104f)
    13 0040103E   push        1
    14 00401040   push        offset string "%d
    " (0042201c)
    15 00401045   call        printf (00401150)
    16 0040104A   add         esp,8
    17 0040104D   jmp         Function+89h (004010a9)
    18 0040104F   cmp         dword ptr [ebp+8],2
    19 00401053   jne         Function+46h (00401066)
    20 00401055   push        2
    21 00401057   push        offset string "%d
    " (0042201c)
    22 0040105C   call        printf (00401150)
    23 00401061   add         esp,8
    24 00401064   jmp         Function+89h (004010a9)
    25 00401066   cmp         dword ptr [ebp+8],3
    26 0040106A   jne         Function+5Dh (0040107d)
    27 0040106C   push        3
    28 0040106E   push        offset string "%d
    " (0042201c)
    29 00401073   call        printf (00401150)
    30 00401078   add         esp,8
    31 0040107B   jmp         Function+89h (004010a9)
    32 0040107D   cmp         dword ptr [ebp+8],4
    33 00401081   jne         Function+74h (00401094)
    34 00401083   push        4
    35 00401085   push        offset string "%d
    " (0042201c)
    36 0040108A   call        printf (00401150)
    37 0040108F   add         esp,8
    38 00401092   jmp         Function+89h (004010a9)
    39 00401094   cmp         dword ptr [ebp+8],5
    40 00401098   jne         Function+89h (004010a9)
    41 0040109A   push        5
    42 0040109C   push        offset string "%d
    " (0042201c)
    43 004010A1   call        printf (00401150)
    44 004010A6   add         esp,8
    45 004010A9   pop         edi
    46 004010AA   pop         esi
    47 004010AB   pop         ebx
    48 004010AC   add         esp,40h
    49 004010AF   cmp         ebp,esp
    50 004010B1   call        __chkesp (004011d0)
    51 004010B6   mov         esp,ebp
    52 004010B8   pop         ebp
    53 004010B9   ret

      下面来一段相同功能的switch语句,再观察反汇编

     1 #include "stdafx.h"
     2 
     3 void Function(int m)
     4 {
     5     switch (m)
     6     {
     7     case 1:
     8         printf("1
    ");
     9         break;
    10     case 2:
    11         printf("2
    ");
    12         break;
    13     case 3:
    14         printf("3
    ");
    15         break;
    16     default:
    17         printf("Error!
    ");
    18         break;
    19     }
    20 }
    21 
    22 int main(int argc, char* argv[])
    23 {
    24     Function(3);
    25     return 0;
    26 }

      反汇编代码如下 

     1 00401020   push        ebp
     2 00401021   mov         ebp,esp
     3 00401023   sub         esp,44h
     4 00401026   push        ebx
     5 00401027   push        esi
     6 00401028   push        edi
     7 00401029   lea         edi,[ebp-44h]
     8 0040102C   mov         ecx,11h
     9 00401031   mov         eax,0CCCCCCCCh
    10 00401036   rep stos    dword ptr [edi]
    11 00401038   mov         eax,dword ptr [ebp+8]
    12 0040103B   mov         dword ptr [ebp-4],eax
    13 0040103E   cmp         dword ptr [ebp-4],1
    14 00401042   je          Function+32h (00401052)
    15 00401044   cmp         dword ptr [ebp-4],2
    16 00401048   je          Function+41h (00401061)
    17 0040104A   cmp         dword ptr [ebp-4],3
    18 0040104E   je          Function+50h (00401070)
    19 00401050   jmp         Function+5Fh (0040107f)
    20 00401052   push        offset string "1
    " (00422f54)
    21 00401057   call        printf (00401150)
    22 0040105C   add         esp,4
    23 0040105F   jmp         Function+6Ch (0040108c)
    24 00401061   push        offset string "4
    " (0042212c)
    25 00401066   call        printf (00401150)
    26 0040106B   add         esp,4
    27 0040106E   jmp         Function+6Ch (0040108c)
    28 00401070   push        offset string "5
    " (0042201c)
    29 00401075   call        printf (00401150)
    30 0040107A   add         esp,4
    31 0040107D   jmp         Function+6Ch (0040108c)
    32 0040107F   push        offset string "Error!
    " (00422fa4)
    33 00401084   call        printf (00401150)
    34 00401089   add         esp,4
    35 0040108C   pop         edi
    36 0040108D   pop         esi
    37 0040108E   pop         ebx
    38 0040108F   add         esp,44h
    39 00401092   cmp         ebp,esp
    40 00401094   call        __chkesp (004011d0)
    41 00401099   mov         esp,ebp
    42 0040109B   pop         ebp
    43 0040109C   ret

       观察反汇编代码可以看到,此时判定状态差别不大,均是cmp,jmp

    三、switch语句大表的产生

      1、基于上例子的基础上,添加case后面的值,一个一个增加,观察反汇编代码的变化(何时生成大表).

       上个例子中,switch语句中,只有3个分支,我们增加一个case看看

     1 #include "stdafx.h"
     2 
     3 void Function(int m)
     4 {
     5     switch (m)
     6     {
     7     case 1:
     8         printf("1
    ");
     9         break;
    10     case 2:
    11         printf("2
    ");
    12         break;
    13     case 3:
    14         printf("3
    ");
    15         break;
    16     case 4:
    17         printf("4
    ");
    18         break;
    19     default:
    20         printf("Error!
    ");
    21         break;
    22     }
    23 }
    24 
    25 int main(int argc, char* argv[])
    26 {
    27     Function(3);
    28     return 0;
    29 }

     

     1 00401020   push        ebp
     2 00401021   mov         ebp,esp
     3 00401023   sub         esp,44h
     4 00401026   push        ebx
     5 00401027   push        esi
     6 00401028   push        edi
     7 00401029   lea         edi,[ebp-44h]
     8 0040102C   mov         ecx,11h
     9 00401031   mov         eax,0CCCCCCCCh
    10 00401036   rep stos    dword ptr [edi]
    11 00401038   mov         eax,dword ptr [ebp+8]
    12 0040103B   mov         dword ptr [ebp-4],eax
    13 0040103E   mov         ecx,dword ptr [ebp-4]
    14 00401041   sub         ecx,1
    15 00401044   mov         dword ptr [ebp-4],ecx
    16 00401047   cmp         dword ptr [ebp-4],3
    17 0040104B   ja          $L539+0Fh (00401093)
    18 0040104D   mov         edx,dword ptr [ebp-4]
    19 00401050   jmp         dword ptr [edx*4+4010B1h]
    20 $L533:
    21 00401057   push        offset string "1
    " (00422034)
    22 0040105C   call        printf (00401140)
    23 00401061   add         esp,4
    24 00401064   jmp         $L539+1Ch (004010a0)
    25 $L535:
    26 00401066   push        offset string "2
    " (00422030)
    27 0040106B   call        printf (00401140)
    28 00401070   add         esp,4
    29 00401073   jmp         $L539+1Ch (004010a0)
    30 $L537:
    31 00401075   push        offset string "3
    " (0042202c)
    32 0040107A   call        printf (00401140)
    33 0040107F   add         esp,4
    34 00401082   jmp         $L539+1Ch (004010a0)
    35 $L539:
    36 00401084   push        offset string "4
    " (00422028)
    37 00401089   call        printf (00401140)
    38 0040108E   add         esp,4
    39 00401091   jmp         $L539+1Ch (004010a0)
    40 00401093   push        offset string "Error!
    " (0042201c)
    41 00401098   call        printf (00401140)
    42 0040109D   add         esp,4

     

    00401038 mov eax,dword ptr [ebp+8]  //将参数m放置eax
    0040103B mov dword ptr [ebp-4],eax  //将eax的值给到局部变量ebp-4
    0040103E mov ecx,dword ptr [ebp-4]  //局部变量的值给ecx
    00401041 sub ecx,1          //ecx的值减去case中最小的常量值
    00401044 mov dword ptr [ebp-4],ecx  //再将ecx的值给局部变量,此时ecx的值为2
    00401047 cmp dword ptr [ebp-4],3    //将局部变量m与3比较,以至于为什么是跟3比较呢?首先会有一张表,这个表记录了每个case分支的函数地址,这个表的首地址是以最下的case + 常量值为首,如果超过这个表,那么则都跳转至default处
    0040104B ja $L539+0Fh (00401093)  //如果高于等于的话,函数则跳转至0x00401096地址处,这个地址其实就是default的位置
    0040104D mov edx,dword ptr [ebp-4]  //将局部变量ebp-4,m的值赋给edx
    00401050 jmp dword ptr [edx*4+4010B1h]  //大表根据这个差值来跳转值那个函数地址

       2、将1中的常量值的顺序打乱,观察反汇编代码(观察顺序是否会影响生成大表).

       为了方便,我增加几句case

     1 #include "stdafx.h"
     2 
     3 void Function(int m)
     4 {
     5     switch (m)
     6     {
     7     case 9:
     8         printf("9
    ");
     9         break;
    10     case 3:
    11         printf("3
    ");
    12         break;
    13     case 7:
    14         printf("7
    ");
    15         break;
    16     case 4:
    17         printf("4
    ");
    18         break;
    19     case 1:
    20         printf("1
    ");
    21         break;
    22     case 2:
    23         printf("2
    ");
    24         break;
    25     case 6:
    26         printf("6
    ");
    27         break;
    28     default:
    29         printf("Error!
    ");
    30         break;
    31     }
    32 }
    33 
    34 int main(int argc, char* argv[])
    35 {
    36     Function(4);
    37     return 0;
    38 }
     1 0040D7D0   push        ebp
     2 0040D7D1   mov         ebp,esp
     3 0040D7D3   sub         esp,44h
     4 0040D7D6   push        ebx
     5 0040D7D7   push        esi
     6 0040D7D8   push        edi
     7 0040D7D9   lea         edi,[ebp-44h]
     8 0040D7DC   mov         ecx,11h
     9 0040D7E1   mov         eax,0CCCCCCCCh
    10 0040D7E6   rep stos    dword ptr [edi]
    11 0040D7E8   mov         eax,dword ptr [ebp+8]
    12 0040D7EB   mov         dword ptr [ebp-4],eax
    13 0040D7EE   mov         ecx,dword ptr [ebp-4]
    14 0040D7F1   sub         ecx,1
    15 0040D7F4   mov         dword ptr [ebp-4],ecx
    16 0040D7F7   cmp         dword ptr [ebp-4],8
    17 0040D7FB   ja          $L545+0Fh (0040d870)
    18 0040D7FD   mov         edx,dword ptr [ebp-4]
    19 0040D800   jmp         dword ptr [edx*4+40D88Eh]
    20 $L533:
    21 0040D807   push        offset string "9
    " (00422f6c)
    22 0040D80C   call        printf (00401140)
    23 0040D811   add         esp,4
    24 0040D814   jmp         $L545+1Ch (0040d87d)
    25 $L535:
    26 0040D816   push        offset string "3
    " (00422144)
    27 0040D81B   call        printf (00401140)
    28 0040D820   add         esp,4
    29 0040D823   jmp         $L545+1Ch (0040d87d)
    30 $L537:
    31 0040D825   push        offset string "7
    " (00422034)
    32 0040D82A   call        printf (00401140)
    33 0040D82F   add         esp,4
    34 0040D832   jmp         $L545+1Ch (0040d87d)
    35 $L539:
    36 0040D834   push        offset string "4
    " (00422024)
    37 0040D839   call        printf (00401140)
    38 0040D83E   add         esp,4
    39 0040D841   jmp         $L545+1Ch (0040d87d)
    40 $L541:
    41 0040D843   push        offset string "1
    " (00422030)
    42 0040D848   call        printf (00401140)
    43 0040D84D   add         esp,4
    44 0040D850   jmp         $L545+1Ch (0040d87d)
    45 $L543:
    46 0040D852   push        offset string "2
    " (0042202c)
    47 0040D857   call        printf (00401140)
    48 0040D85C   add         esp,4
    49 0040D85F   jmp         $L545+1Ch (0040d87d)
    50 $L545:
    51 0040D861   push        offset string "5
    " (00422028)
    52 0040D866   call        printf (00401140)
    53 0040D86B   add         esp,4
    54 0040D86E   jmp         $L545+1Ch (0040d87d)
    55 0040D870   push        offset string "Error!
    " (0042201c)
    56 0040D875   call        printf (00401140)
    57 0040D87A   add         esp,4

      观察大表,以及反汇编代码,很显然,switch语句中,case的顺序不会影响到大表的生成,大表的生成根据地址而来

      

       3、将case后面的值改成从100开始到109,观察汇编变化(观察值较大时是否生成大表).

     1 #include "stdafx.h"
     2 
     3 void Function(int m)
     4 {
     5     switch (m)
     6     {
     7     case 101:
     8         printf("101
    ");
     9         break;
    10     case 102:
    11         printf("102
    ");
    12         break;
    13     case 103:
    14         printf("103
    ");
    15         break;
    16     case 104:
    17         printf("104
    ");
    18         break;
    19     case 105:
    20         printf("105
    ");
    21         break;
    22     case 106:
    23         printf("106
    ");
    24         break;
    25     case 107:
    26         printf("107
    ");
    27         break;
    28     case 108:
    29         printf("108
    ");
    30         break;
    31     case 109:
    32         printf("109
    ");
    33         break;
    34     case 110:
    35         printf("110
    ");
    36         break;
    37     default:
    38         printf("Error!
    ");
    39         break;
    40     }
    41 }
    42 
    43 int main(int argc, char* argv[])
    44 {
    45     Function(104);
    46     return 0;
    47 }

     

       4、将连续的10项中抹去1项或者2项,观察反汇编有无变化(观察大表空缺位置的处理)

     1 #include "stdafx.h"
     2 
     3 void Function(int m)
     4 {
     5     switch (m)
     6     {
     7     case 101:
     8         printf("101
    ");
     9         break;
    10         /*
    11     case 102:
    12         printf("102
    ");
    13         break;
    14         */
    15     case 103:
    16         printf("103
    ");
    17         break;
    18     case 104:
    19         printf("104
    ");
    20         break;
    21     case 105:
    22         printf("105
    ");
    23         break;
    24     case 106:
    25         printf("106
    ");
    26         break;
    27     case 107:
    28         printf("107
    ");
    29         break;
    30     case 108:
    31         printf("108
    ");
    32         break;
    33     case 109:
    34         printf("109
    ");
    35         break;
    36     case 110:
    37         printf("110
    ");
    38         break;
    39     default:
    40         printf("Error!
    ");
    41         break;
    42     }
    43 }
    44 
    45 int main(int argc, char* argv[])
    46 {
    47     Function(104);
    48     return 0;
    49 }

      抹去三项看看?

     1 #include "stdafx.h"
     2 
     3 void Function(int m)
     4 {
     5     switch (m)
     6     {
     7     case 101:
     8         printf("101
    ");
     9         break;
    10         /*
    11     case 102:
    12         printf("102
    ");
    13         break;
    14     case 103:
    15         printf("103
    ");
    16         break;
    17     case 104:
    18         printf("104
    ");
    19         break;
    20         */
    21     case 105:
    22         printf("105
    ");
    23         break;
    24     case 106:
    25         printf("106
    ");
    26         break;
    27     case 107:
    28         printf("107
    ");
    29         break;
    30     case 108:
    31         printf("108
    ");
    32         break;
    33     case 109:
    34         printf("109
    ");
    35         break;
    36     case 110:
    37         printf("110
    ");
    38         break;
    39     default:
    40         printf("Error!
    ");
    41         break;
    42     }
    43 }
    44 
    45 int main(int argc, char* argv[])
    46 {
    47     Function(104);
    48     return 0;
    49 }

       经过上面两个例子可以看出,被抹除掉的项按照default来处理了,我们再抹去两项看看

       依旧还是生成大表,我们接着再抹除两个,试试看,看编译器是否还是给我们生成大表?

      5、在10项中连续抹去,不要抹去最大值和最小值(观察何时生成小表).

     1 #include "stdafx.h"
     2 
     3 void Function(int m)
     4 {
     5     switch (m)
     6     {
     7     case 101:
     8         printf("101
    ");
     9         break;
    10         /*
    11     case 102:
    12         printf("102
    ");
    13         break;
    14     case 103:
    15         printf("103
    ");
    16         break;
    17     case 104:
    18         printf("104
    ");
    19         break;
    20     case 105:
    21         printf("105
    ");
    22         break;
    23     case 106:
    24         printf("106
    ");
    25         break;    
    26     case 107:
    27         printf("107
    ");
    28         break;
    29         */
    30     case 108:
    31         printf("108
    ");
    32         break;
    33     case 109:
    34         printf("109
    ");
    35         break;
    36     case 110:
    37         printf("110
    ");
    38         break;
    39     default:
    40         printf("Error!
    ");
    41         break;
    42     }
    43 }
    44 
    45 int main(int argc, char* argv[])
    46 {
    47     Function(109);
    48     return 0;
    49 }

      可以看到,由于编译器只采用dl用来存储小表,所以当间隔255个数之后,小表也将不负存在了

      6、将case后面常量表达式改成毫不连续的值,观察反汇编变化.

      这种switch...case..语句其实基本见不着,因为丝毫无意义

     1 #include "stdafx.h"
     2 
     3 void Function(int m)
     4 {
     5     switch (m)
     6     {
     7     case 5:
     8         printf("101
    ");
     9         break;
    10     case 888:
    11         printf("108
    ");
    12         break;
    13     case 3200:
    14         printf("109
    ");
    15         break;
    16     case 5000:
    17         printf("110
    ");
    18         break;
    19     case 9000:
    20         printf("110
    ");
    21         break;
    22     case 19200:
    23         printf("110
    ");
    24         break;
    25     default:
    26         printf("Error!
    ");
    27         break;
    28     }
    29 }
    30 
    31 int main(int argc, char* argv[])
    32 {
    33     Function(109);
    34     return 0;
    35 }
     1 00401020   push        ebp
     2 00401021   mov         ebp,esp
     3 00401023   sub         esp,44h
     4 00401026   push        ebx
     5 00401027   push        esi
     6 00401028   push        edi
     7 00401029   lea         edi,[ebp-44h]
     8 0040102C   mov         ecx,11h
     9 00401031   mov         eax,0CCCCCCCCh
    10 00401036   rep stos    dword ptr [edi]
    11 00401038   mov         eax,dword ptr [ebp+8]
    12 0040103B   mov         dword ptr [ebp-4],eax
    13 0040103E   cmp         dword ptr [ebp-4],1388h
    14 00401045   jg          Function+4Ah (0040106a)
    15 00401047   cmp         dword ptr [ebp-4],1388h
    16 0040104E   je          Function+8Bh (004010ab)
    17 00401050   cmp         dword ptr [ebp-4],5
    18 00401054   je          Function+5Eh (0040107e)
    19 00401056   cmp         dword ptr [ebp-4],378h
    20 0040105D   je          Function+6Dh (0040108d)
    21 0040105F   cmp         dword ptr [ebp-4],0C80h
    22 00401066   je          Function+7Ch (0040109c)
    23 00401068   jmp         Function+0B8h (004010d8)
    24 0040106A   cmp         dword ptr [ebp-4],2328h
    25 00401071   je          Function+9Ah (004010ba)
    26 00401073   cmp         dword ptr [ebp-4],4B00h
    27 0040107A   je          Function+0A9h (004010c9)
    28 0040107C   jmp         Function+0B8h (004010d8)
    29 0040107E   push        offset string "101
    " (00422040)
    30 00401083   call        printf (00401160)
    31 00401088   add         esp,4
    32 0040108B   jmp         Function+0C5h (004010e5)
    33 0040108D   push        offset string "108
    " (00422038)
    34 00401092   call        printf (00401160)
    35 00401097   add         esp,4
    36 0040109A   jmp         Function+0C5h (004010e5)
    37 0040109C   push        offset string "109
    " (00422030)
    38 004010A1   call        printf (00401160)
    39 004010A6   add         esp,4
    40 004010A9   jmp         Function+0C5h (004010e5)
    41 004010AB   push        offset string "110
    " (00422028)
    42 004010B0   call        printf (00401160)
    43 004010B5   add         esp,4
    44 004010B8   jmp         Function+0C5h (004010e5)
    45 004010BA   push        offset string "110
    " (00422028)
    46 004010BF   call        printf (00401160)
    47 004010C4   add         esp,4
    48 004010C7   jmp         Function+0C5h (004010e5)
    49 004010C9   push        offset string "110
    " (00422028)
    50 004010CE   call        printf (00401160)
    51 004010D3   add         esp,4
    52 004010D6   jmp         Function+0C5h (004010e5)
    53 004010D8   push        offset string "Error!
    " (0042201c)
    54 004010DD   call        printf (00401160)
    55 004010E2   add         esp,4
    56 004010E5   pop         edi
    57 004010E6   pop         esi
    58 004010E7   pop         ebx
    59 004010E8   add         esp,44h
  • 相关阅读:
    mysql面试题
    Zookeeper与Kafka基础概念和原理
    Docker资源限制
    企业级仓库harbor搭建
    基于容器制作镜像
    docker基础学习(一)
    docker往阿里云推镜像和打包镜像
    Dockfile制作镜像
    算法Sedgewick第四版-第1章基础-006一封装输出(文件)
    算法Sedgewick第四版-第1章基础-005一封装输入(可以文件,jar包里的文件或网址)
  • 原文地址:https://www.cnblogs.com/Reverse-xiaoyu/p/11711393.html
Copyright © 2011-2022 走看看