天天看點

Switch結構學習筆記

一、case 小于等于3項的情況

先看第一個程式段:

switch (nscore)
    {
    case 1:
        ntmpNum = 1;
        break;
    case 3:
        ntmpNum = 3;
        break;
    case 4:
        ntmpNum = 4;
        break;
    default:
        ntmpNum = 10;
    }
printf("%d", ntmpNum); // 要調用一下ntmpNum,否則上面的switch會被優化掉      

OD

載入,看一下:

00401013 >|.  E8 0F010000     call    00401127                         ;  scanf
00401018  |.  8B4424 08      mov     eax, dword ptr [esp+8]
0040101C  |?  83C4 08       add     esp, 8                                           ; 上面scanf是C類調用
0040101F  |?  48            dec     eax                  ; 通過EAX的減法來判斷屬于哪個分支
00401020  |?  74 1D         je      short 0040103F
00401022  |.  83E8 02        sub     eax, 2
00401025  \.  74 11           je      short 00401038
00401027      48            dec     eax
00401028      74 07          je      short 00401031
0040102A      B8 0A000000   mov     eax, 0A
0040102F      EB 13          jmp     short 00401044   ;  break
00401031  |.  B8 04000000     mov     eax, 4
00401036  |.  EB 0C          jmp     short 00401044
00401038  |?  B8 03000000    mov     eax, 3
0040103D  |?  EB 05         jmp     short 00401044
0040103F  |?  B8 01000000    mov     eax, 1
00401044  |.  50             push    eax
00401045  |?  68 38904000    push    00409038                         ;  ASCII "%d"      

這種情況跟

if

差不多,不多分析。

二、case項多于3項且有規律的情況

看第二段代碼:

scanf("%d", &nscore);
switch (nscore)
{
case 3:
  ntmpNum = 1;
  break;
case 1:
  ntmpNum = 3;
  break;
case 5:
  ntmpNum = 4;
  break;
case 9:
  ntmpNum = 4;
  break;
case 7:
  ntmpNum = 4;
  break;
case 11:
  ntmpNum = 4;
  break;
default:
  ntmpNum = 10;
}
printf("%d", ntmpNum); // 要調用一下ntmpNum,否則上面的switch會被優化掉      

這段代碼,我們将有規律的case打亂順序,然後看編譯器是怎麼處理的。

OD中檢視反彙編形式:

0040100E  |.  68 38904000   push    00409038            ;  ASCII "%d"
00401013  |.  E8 3F010000   call    00401157             ;  scanf
00401018  |.  8B4C24 08     mov     ecx, dword ptr [esp+8];  得到輸入的内容
0040101C  |.  83C4 08       add     esp, 8
0040101F  |.  8D41 FF       lea     eax, dword ptr [ecx-1];  輸入的内容-1; Switch (cases 1..B)
00401022  |.  83F8 0A       cmp     eax, 0A
00401025  |.  77 1C         ja      short 00401043
00401027  |.  FF2485 641040>jmp   dword ptr [eax*4+401064];  查表,跳轉到對應的CASE中
0040102E  |>  B8 01000000   mov     eax, 1             ;  Case 3 of switch 0040101F
00401033  |.  EB 13         jmp     short 00401048
00401035  |>  B8 03000000   mov     eax, 3             ;  Case 1 of switch 0040101F
0040103A  |.  EB 0C         jmp     short 00401048
0040103C  |>  B8 04000000   mov     eax, 4             ;  Cases 5,7,9,B of switch 0040101F
00401041  |.  EB 05          jmp     short 00401048
00401043  |>  B8 0A000000   mov     eax, 0A        ;  Default case of switch 0040101F
00401048  |>  50            push    eax
00401049  |.  68 38904000    push    00409038        ;  ASCII "%d"
0040104E  |.  E8 D3000000   call    00401126         ;  printf      

跟随下這個表,我們發現,這個表就在調用它的函數後,如下:

跳轉表:

00401064  00401035  switch.00401035
00401068  00401043  switch.00401043          插入的是default分支的首位址
0040106C  0040102E  switch.0040102E
00401070  00401043  switch.00401043          插入的是default分支的首位址
00401074  0040103C  switch.0040103C
00401078  00401043  switch.00401043          插入的是default分支的首位址
0040107C  0040103C  switch.0040103C
00401080  00401043  switch.00401043          插入的是default分支的首位址
00401084  0040103C  switch.0040103C
00401088  00401043  switch.00401043          插入的是default分支的首位址
0040108C  0040103C  switch.0040103C      

認真對比一下這個表,發現,它先是對case後的常量排序,然後再将對應的處理代碼的首位址寫成一個表,通過jmp dword ptr [eax*4+401064] 查表直接進入到對應的case中。對于預設的case(我們是間隔2遞增的case)在表中填充的是default分支的首位址。

三、多于三項部分有規律的情況

上個我們發現,它會給預設的case表項中填補default分支的首位址,那我們将這個間隔調大,觀察一下編譯器會怎麼處理,代碼段如下:

scanf("%d", &nscore);
    switch (nscore)
    {
    case 1:
        ntmpNum = 1;
        break;
    case 2:
        ntmpNum = 2;
        break;
    case 3:
        ntmpNum = 3;
        break;
    //這裡丢失20多個case
    case 26:
        ntmpNum = 26;
        break;
    case 27:
        ntmpNum = 27;
        break;
    case 28:
        ntmpNum = 28;
        break;
    default:
        ntmpNum = 10;
    }
printf("%d", ntmpNum); // 要調用一下ntmpNum,否則上面的switch會被優化掉      

反彙編觀察一下:

0040100E    68 38904000     push    00409038                     ; ASCII "%d"
00401013    E8 6F010000     call    00401187                      ; scanf
00401018    8B4C24 08       mov     ecx, dword ptr [esp+8]           ; 得到輸入的内容
0040101C    83C4 08         add     esp, 8
0040101F    8D41 FF         lea     eax, dword ptr [ecx-1]           ; 輸入的内容-1
00401022    83F8 1B         cmp     eax, 1B
00401025    77 39           ja      short 00401060
00401027    33D2            xor     edx, edx
00401029    8A90 9C104000   mov     dl, byte ptr [eax+40109C]  ; 檢索case的下标索引值表
;它參與運算從位址表中找到對應的case位址
0040102F    FF2495 80104000 jmp     dword ptr [edx*4+401080] 
; 通過值表填充的CASE索引值,查位址表
00401036    B8 01000000     mov     eax, 1
0040103B    EB 28           jmp     short 00401065                ; break
0040103D    B8 02000000     mov     eax, 2
00401042    EB 21           jmp     short 00401065
00401044    B8 03000000     mov     eax, 3
00401049    EB 1A           jmp     short 00401065
0040104B    B8 1A000000     mov     eax, 1A
00401050    EB 13           jmp     short 00401065
00401052    B8 1B000000     mov     eax, 1B
00401057    EB 0C           jmp     short 00401065
00401059    B8 1C000000     mov     eax, 1C
0040105E    EB 05           jmp     short 00401065
00401060    B8 0A000000     mov     eax, 0A
00401065    50              push    eax
00401066    68 38904000     push    00409038                         ; ASCII "%d"      

下标索引表:

0040109C    00          DB 00 case 1的索引值
0040109D    01          DB 01 case 2的索引值
0040109E    02          DB 02 case 3的索引值
0040109F    06          DB 06 下面全部填充default的索引值
004010A0    06          DB 06
...
004010B4    06          DB 06
004010B5    03          DB 03 case 4的索引值
004010B6    04          DB 04 case 5的索引值
004010B7    05          DB 05 case 6的索引值      

跳轉位址表:

00401080  00401036  switch.00401036
00401084  0040103D  switch.0040103D
00401088  00401044  switch.00401044
0040108C  0040104B  switch.0040104B
00401090  00401052  switch.00401052
00401094  00401059  switch.00401059
00401098  00401060  switch.00401060      

這樣查兩個表,預設的

case

項在索引表中插入

 default 

的索引值,這樣每個

case

項就節省了

3

個位元組的空間。

mov     dl, byte ptr [eax+40109C]   // 40109C是索引表首位址
jmp     dword ptr [edx*4+401080]  // 401080是跳轉位址表的首位址。      

這樣,就可以定位到對應的case項了。

我們繼續增大這個case之間的差距,讓它超過255,代碼段如下:

00401018    8B4424 08       mov     eax, dword ptr [esp+8]  ; 得到輸入的内容
0040101C    83C4 08         add     esp, 8
0040101F    3D 46010000     cmp     eax, 146        ; 判斷是不是大case中最小的
00401024    7F 27           jg      short 0040104D   ; 如果大于,就進入大case中比較
00401026    74 1E           je      short 00401046    ; 如果相等就直接進入0x146的case代碼段
00401028    48              dec     eax                    ; 否則就到小的case段中比較。
00401029    74 14           je      short 0040103F
0040102B    48              dec     eax
0040102C    74 0A           je      short 00401038
0040102E    48              dec     eax
0040102F    75 26           jnz     short 00401057    ; default了。
00401031    B8 03000000     mov     eax, 3
00401036    EB 32           jmp     short 0040106A
00401038    B8 02000000     mov     eax, 2
0040103D    EB 2B           jmp     short 0040106A
0040103F    B8 01000000     mov     eax, 1
00401044    EB 24           jmp     short 0040106A
00401046    B8 1A000000     mov     eax, 1A
0040104B    EB 1D           jmp     short 0040106A
0040104D    2D 47010000     sub     eax, 147    
; 減去一個case項值,得到一個內插補點,這樣就可以判斷大case了。
00401052    74 11            je      short 00401065
00401054    48              dec     eax
00401055    74 07            je      short 0040105E
00401057    B8 0A000000     mov     eax, 0A
0040105C    EB 0C           jmp     short 0040106A
0040105E    B8 1C000000     mov     eax, 1C
00401063    EB 05           jmp     short 0040106A
00401065    B8 1B000000     mov     eax, 1B
0040106A    50              push    eax
0040106B    68 38904000      push    00409038            ; ASCII "%d"
00401070    E8 B1000000     call    00401126      

看到了麼?這裡就分成了兩段,每段當做if來處理的,我想應該是我們每段的case數量太少,我們讓上面的case 數量大于3個試試,看看會不會是隻要大于三項的有規律case就查表,少于等于3項的就當成if來處理。

代碼段如下:

scanf("%d", &nscore);
   
    switch (nscore)
    {
    case 1:
        ntmpNum = 1;
        break;
    case 2:
        ntmpNum = 2;
        break;
    case 3:
        ntmpNum = 3;
        break;
    case 4:
        ntmpNum = 4;
        break;
    case 5:
        ntmpNum = 5;
        break;
    //這裡丢失幾個case
    case 326:
        ntmpNum = 326;
        break;
    case 327:
        ntmpNum = 327;
        break;
    case 328:
        ntmpNum = 328;
        break;
    default:
        ntmpNum = 10;
    }
 
printf("%d", ntmpNum); // 要調用一下ntmpNum,否則上面的switch會被優化掉      

反彙編看下效果:

0040100E    68 38904000     push    00409038                         ; ASCII "%d"
00401013    E8 5F010000     call    00401177                         ; scanf
00401018    8B4424 08       mov     eax, dword ptr [esp+8]           ; 得到輸入的内容
0040101C    83C4 08         add     esp, 8
0040101F    3D 46010000     cmp     eax, 146                      
00401024    7F 39           jg      short 0040105F
00401026    74 30           je      short 00401058
00401028    48              dec     eax
00401029    83F8 04         cmp     eax, 4
0040102C    77 3B           ja      short 00401069
0040102E    FF2485 98104000 jmp     dword ptr [eax*4+401098]
00401035    B8 01000000     mov     eax, 1
0040103A    EB 40           jmp     short 0040107C
0040103C    B8 02000000     mov     eax, 2
00401041    EB 39           jmp     short 0040107C
00401043    B8 03000000     mov     eax, 3
00401048    EB 32           jmp     short 0040107C
0040104A    B8 04000000     mov     eax, 4
0040104F    EB 2B           jmp     short 0040107C
00401051    B8 05000000     mov     eax, 5
00401056    EB 24           jmp     short 0040107C
00401058    B8 46010000     mov     eax, 146
0040105D    EB 1D           jmp     short 0040107C
0040105F    2D 47010000     sub     eax, 147
00401064    74 11           je      short 00401077
00401066    48              dec     eax
00401067    74 07           je      short 00401070
00401069    B8 0A000000     mov     eax, 0A
0040106E    EB 0C           jmp     short 0040107C
00401070    B8 48010000     mov     eax, 148
00401075    EB 05           jmp     short 0040107C
00401077    B8 47010000     mov     eax, 147
0040107C    50              push    eax
0040107D    68 38904000     push    00409038                         ; ASCII "%d"
00401082    E8 BF000000     call    00401146      

跳轉表如下:

00401098  00401035  switch.00401035
0040109C  0040103C  switch.0040103C
004010A0  00401043  switch.00401043
004010A4  0040104A  switch.0040104A
004010A8  00401051  switch.00401051      

哈哈,不多說了,我們看下無規律的情況。

四、對于毫無規律的情況。

通過上個例子的分析,我們大概可以猜出來,編譯器會擇優選擇查表,查雙表來對部分離得比較近的case項作處理,最後才考慮毫無規律的情況,為了提高我們這次測試的成功率,我們讓每個相鄰的case項內插補點都超過255,為了避免switch當做if來處理,我們多寫幾個case,具體代碼段如下:

scanf("%d", &nscore);
   
    switch (nscore)
    {
    case 1:
        ntmpNum = 1;
        break;
    case 300:
        ntmpNum = 300;
        break;
    case 570:
        ntmpNum = 570;
        break;
    case 830:
        ntmpNum = 830;
        break;
    case 1094:
        ntmpNum = 1094;
        break;
    case 1314:
        ntmpNum = 32;
        break;
    case 1614:
        ntmpNum = 1614;
        break;
    case 1894:
        ntmpNum = 1894;
        break;
    case 2199:
        ntmpNum = 2199;
        break;
    case 2578:
        ntmpNum = 2578;
        break;
    case 2800:
        ntmpNum = 2800;
        break;
    case 3178:
        ntmpNum = 3178;
        break;
    case 3568:
        ntmpNum = 3568;
        break;
    case 3856:
        ntmpNum = 3856;
        break;
    case 4212:
        ntmpNum = 4212;
        break;
    case 4679:
        ntmpNum = 4679;
        break;
    case 5050:
        ntmpNum = 5050;
        break;
    case 5486:
        ntmpNum = 5486;
        break;
    case 5797:
        ntmpNum = 5797;
        break;
    case 6089:
        ntmpNum = 6089;
        break;
    case 6713:
        ntmpNum = 6713;
        break;
    case 8425:
        ntmpNum = 8425;
        break;
    case 8973:
        ntmpNum = 8973;
        break;
    case 9545:
        ntmpNum = 9545;
        break;
    case 9987:
        ntmpNum = 9987;
        break;
    case 11254:
        ntmpNum = 11254;
        break;
    case 12489:
        ntmpNum = 12489;
        break;
    case 15798:
        ntmpNum = 15798;
        break;
    case 26874:
        ntmpNum = 26874;
        break;
    case 34721:
        ntmpNum = 34721;
        break;
    case 39681:
        ntmpNum = 39681;
        break;
    default:
        ntmpNum = 10;
    }
 
    printf("%d", ntmpNum); // 要調用一下ntmpNum,否則上面的switch會被優化掉      

反彙編結果:

0040100E  |.  68 38A04000   push    0040A038   ASCII "%d"
00401013  |.  E8 EF020000   call    00401307
00401018  |.  8B4424 08     mov     eax, dword ptr [esp+8] ;  得到輸入的内容
0040101C  |.  83C4 08       add     esp, 8
0040101F  |.  3D 47120000   cmp     eax, 1247     ;  0x1247是case後常量中間的一個元素
; Switch (cases 1..9B01)
00401024  |.  0F8F 16010000 jg      00401140    ;  如果大于就比較0x2549
0040102A  |.  0F84 06010000 je      00401136    ;  等于就跳到對應的case中
00401030  |.  3D 66070000   cmp     eax, 766    ;  如果小于就再跟766比較
00401035  |.  0F8F 84000000 jg      004010BF    ;  同上,周遊二叉樹的方法……
0040103B  |.  74 78         je      short 004010B5
0040103D  |.  3D 3E030000   cmp     eax, 33E
00401042  |.  7F 3F         jg      short 00401083
00401044  |.  74 33         je      short 00401079
00401046  |.  48            dec     eax       
;  用輸入的資料依次減去某個CASE後的常量值,來判斷是否為0……
00401047  |.  74 26         je      short 0040106F
;  是以,看到這寄存器連續做減法運算應該就是這種switch的特征了吧……
00401049  |.  2D 2B010000   sub     eax, 12B
0040104E  |.  74 15         je      short 00401065
00401050  |.  2D 0E010000   sub     eax, 10E
00401055  |.  0F85 A9010000 jnz     00401204
0040105B  |.  B8 3A020000   mov     eax, 23A    ;  Case 23A of switch 0040101F
00401060  |.  E9 B9010000   jmp     0040121E
00401065  |>  B8 2C010000   mov     eax, 12C    ;  Case 12C of switch 0040101F
0040106A  |.  E9 AF010000   jmp     0040121E
0040106F  |>  B8 01000000   mov     eax, 1      ;  Case 1 of switch 0040101F
00401074  |.  E9 A5010000   jmp     0040121E
00401079  |>  B8 3E030000   mov     eax, 33E    ;  Case 33E of switch 0040101F
0040107E  |.  E9 9B010000   jmp     0040121E
00401083  |>  3D 46040000   cmp     eax, 446
00401088  |.  74 21         je      short 004010AB
0040108A  |.  3D 22050000   cmp     eax, 522
0040108F  |.  74 10         je      short 004010A1
00401091  |.  3D 4E060000   cmp     eax, 64E
00401096  |.  0F85 68010000 jnz     00401204
0040109C  |.  E9 7D010000   jmp     0040121E   ;  Case 64E of switch 0040101F
004010A1  |>  B8 20000000   mov     eax, 20    ;  Case 522 of switch 0040101F
004010A6  |.  E9 73010000   jmp     0040121E
004010AB  |>  B8 46040000   mov     eax, 446    ;  Case 446 of switch 0040101F
004010B0  |.  E9 69010000   jmp     0040121E
004010B5  |>  B8 66070000   mov     eax, 766     ;  Case 766 of switch 0040101F
004010BA  |.  E9 5F010000   jmp     0040121E
004010BF  |>  3D 6A0C0000   cmp     eax, 0C6A
004010C4  |.  7F 3E         jg      short 00401104
004010C6  |.  74 32         je      short 004010FA
004010C8  |.  3D 97080000   cmp     eax, 897
004010CD  |.  74 21         je      short 004010F0
004010CF  |.  3D 120A0000   cmp     eax, 0A12
004010D4  |.  74 10         je      short 004010E6
004010D6  |.  3D F00A0000   cmp     eax, 0AF0
004010DB  |.  0F85 23010000 jnz     00401204
004010E1  |.  E9 38010000   jmp     0040121E     ;  Case AF0 of switch 0040101F
004010E6  |>  B8 120A0000   mov     eax, 0A12    ;  Case A12 of switch 0040101F
004010EB  |.  E9 2E010000   jmp     0040121E
004010F0  |>  B8 97080000   mov     eax, 897      ;  Case 897 of switch 0040101F
004010F5  |.  E9 24010000   jmp     0040121E
004010FA  |>  B8 6A0C0000   mov     eax, 0C6A    ;  Case C6A of switch 0040101F
004010FF  |.  E9 1A010000   jmp     0040121E
00401104  |>  3D F00D0000   cmp     eax, 0DF0
00401109  |.  74 21         je      short 0040112C
0040110B  |.  3D 100F0000   cmp     eax, 0F10
00401110  |.  74 10         je      short 00401122
00401112  |.  3D 74100000   cmp     eax, 1074
00401117  |.  0F85 E7000000 jnz     00401204
0040111D  |.  E9 FC000000   jmp     0040121E    ;  Case 1074 of switch 0040101F
00401122  |>  B8 100F0000   mov     eax, 0F10    ;  Case F10 of switch 0040101F
00401127  |.  E9 F2000000   jmp     0040121E
0040112C  |>  B8 F00D0000   mov     eax, 0DF0   ;  Case DF0 of switch 0040101F
00401131  |.  E9 E8000000   jmp     0040121E
00401136  |>  B8 47120000   mov     eax, 1247     ;  Case 1247 of switch 0040101F
0040113B  |.  E9 DE000000   jmp     0040121E
00401140  |>  3D 49250000   cmp     eax, 2549
00401145  |.  7F 73         jg      short 004011BA
00401147  |.  74 6A         je      short 004011B3
00401149  |.  3D C9170000   cmp     eax, 17C9
0040114E  |.  7F 3E         jg      short 0040118E
00401150  |.  74 32         je      short 00401184
00401152  |.  3D BA130000   cmp     eax, 13BA
00401157  |.  74 21         je      short 0040117A
00401159  |.  3D 6E150000   cmp     eax, 156E
0040115E  |.  74 10         je      short 00401170
00401160  |.  3D A5160000   cmp     eax, 16A5
00401165  |.  0F85 99000000 jnz     00401204
0040116B  |.  E9 AE000000   jmp     0040121E   ;  Case 16A5 of switch 0040101F
00401170  |>  B8 6E150000   mov     eax, 156E   ;  Case 156E of switch 0040101F
00401175  |.  E9 A4000000   jmp     0040121E
0040117A  |>  B8 BA130000   mov     eax, 13BA  ;  Case 13BA of switch 0040101F
0040117F  |.  E9 9A000000   jmp     0040121E
00401184  |>  B8 C9170000   mov     eax, 17C9   ;  Case 17C9 of switch 0040101F
00401189  |.  E9 90000000   jmp     0040121E
0040118E  |>  3D 391A0000   cmp     eax, 1A39
00401193  |.  74 17         je      short 004011AC
00401195  |.  3D E9200000   cmp     eax, 20E9
0040119A  |.  74 09         je      short 004011A5
0040119C  |.  3D 0D230000   cmp     eax, 230D
004011A1  |.  75 61         jnz     short 00401204
004011A3  |.  EB 79         jmp     short 0040121E  ;  Case 230D of switch 0040101F
004011A5  |>  B8 E9200000   mov     eax, 20E9      ;  Case 20E9 of switch 0040101F
004011AA  |.  EB 72         jmp     short 0040121E
004011AC  |>  B8 391A0000   mov     eax, 1A39     ;  Case 1A39 of switch 0040101F
004011B1  |.  EB 6B         jmp     short 0040121E
004011B3  |>  B8 49250000   mov     eax, 2549       ;  Case 2549 of switch 0040101F
004011B8  |.  EB 64         jmp     short 0040121E
004011BA  |>  3D B63D0000   cmp     eax, 3DB6
004011BF  |.  7F 2E         jg      short 004011EF
004011C1  |.  74 25         je      short 004011E8
004011C3  |.  3D 03270000   cmp     eax, 2703
004011C8  |.  74 17         je      short 004011E1
004011CA  |.  3D F62B0000   cmp     eax, 2BF6
004011CF  |.  74 09         je      short 004011DA
004011D1  |.  3D C9300000   cmp     eax, 30C9
004011D6  |.  75 2C         jnz     short 00401204
004011D8  |.  EB 44         jmp     short 0040121E   ;  Case 30C9 of switch 0040101F
004011DA  |>  B8 F62B0000   mov     eax, 2BF6      ;  Case 2BF6 of switch 0040101F
004011DF  |.  EB 3D         jmp     short 0040121E
004011E1  |>  B8 03270000   mov     eax, 2703       ;  Case 2703 of switch 0040101F
004011E6  |.  EB 36         jmp     short 0040121E
004011E8  |>  B8 B63D0000   mov     eax, 3DB6  ;  Case 3DB6 of switch 0040101F
004011ED  |.  EB 2F         jmp     short 0040121E
004011EF  |>  3D FA680000   cmp     eax, 68FA
004011F4  |.  74 23         je      short 00401219
004011F6  |.  3D A1870000   cmp     eax, 87A1
004011FB  |.  74 15         je      short 00401212
004011FD  |.  3D 019B0000   cmp     eax, 9B01
00401202  |.  74 07         je      short 0040120B
00401204  |>  B8 0A000000   mov     eax, 0A  ;  Default case of switch 0040101F
00401209  |.  EB 13         jmp     short 0040121E
0040120B  |>  B8 019B0000   mov     eax, 9B01     ;  Case 9B01 of switch 0040101F
00401210  |.  EB 0C         jmp     short 0040121E
00401212  |>  B8 A1870000   mov     eax, 87A1     ;  Case 87A1 of switch 0040101F
00401217  |.  EB 05         jmp     short 0040121E
00401219  |>  B8 FA680000   mov     eax, 68FA     ;  Case 68FA of switch 0040101F
0040121E  |>  50            push    eax
0040121F  |.  68 38A04000   push    0040A038    ;  ASCII "%d"
00401224  |.  E8 AD000000   call    004012D6      

這個看起來很麻煩哦,仔細觀察下,像是在周遊二叉樹,又像是二分法排序,嘿嘿,可以看得出來這個是以最高效的方式找到相應的

case

項。

Switch結構學習筆記

五、小結

              通過上面幾個小例子的分析,我對編譯器處理switch結構的流程大概有了了解,對于一堆無規律的case,編譯器會:

1、  先對case後的常量排序

2、  對小于3個相連的case常量仿照if結構(最迅速)

3、  對于多于三個的case相連或差距很小的case常量,它會建立跳轉表,不存在的常量位址填補default段的首位址。(效率很高,不用每個項目都比較)

4、  對于間距小于255但也很大的case常量會再額外建立一個索引表,不存在的索引填補default索引。

(比方案3節省位址空間,效率不如3。)

5、  最後處理毫無規律且間距大于255的case項(最不效率)