C基础反汇编
switch
switch性能高于if语句的原因在于在case值较为连续的时候会生成值连续的大表,用switch的参数减去第一个最小的case值,和最大值进行比较,小于等于的话在表的范围内寻址即可[ecx*4+0F44D04h] 。牺牲内存空间,提升效率,以空间换时间。有时间隔较大的还需要生成小表来记录大表的偏移量,省去大表的许多数据。小表记录偏移量的最大值为FF。
int main(int argc, char *argv[])
{
switch (1)
{
case 1:
printf("111111\n");
break;
case 2:
printf("222222\n");
break;
case 3:
printf("333333\n");
break;
case 4:
printf("444444\n");
break;
case 5:
printf("555555\n");
break;
default:
break;
}
system("pause");
return 0;
}
switch (1)
00F44C5E mov dword ptr [ebp-0C4h],1
00F44C68 mov eax,dword ptr [ebp-0C4h]
00F44C6E sub eax,1
00F44C71 mov dword ptr [ebp-0C4h],eax
00F44C77 cmp dword ptr [ebp-0C4h],4
00F44C7E ja $LN8+0Dh (0F44CD6h)
00F44C80 mov ecx,dword ptr [ebp-0C4h]
00F44C86 jmp dword ptr [ecx*4+0F44D04h]
什么时候会生成大表:case过少的时候并不生成大表(一般情况下,在vc与vs中,4case就可以生成大表了),而是类似于if的逐个比较,区别就是比较部分与每个的任务部分分开了。
switch (1)
{
case 1:
printf("111111\n");
break;
case 2:
printf("222222\n");
break;
case 3:
printf("333333\n");
break;
default:
break;
}
switch (1)
00B64C5E mov dword ptr [ebp-0C4h],1
00B64C68 cmp dword ptr [ebp-0C4h],1
00B64C6F je main+45h (0B64C85h)
00B64C71 cmp dword ptr [ebp-0C4h],2
00B64C78 je main+54h (0B64C94h)
00B64C7A cmp dword ptr [ebp-0C4h],3
00B64C81 je main+63h (0B64CA3h)
00B64C83 jmp main+70h (0B64CB0h)顺序不会影响生成大表:观察内存可以发现case数值顺序并不会影响到大表的生成,编译器会自动在大表内按照case值大小进行排序的。
switch (1)
{
case 4:
printf("444444\n");
break;
case 2:
printf("222222\n");
break;
case 3:
printf("333333\n");
break;
case 1:
printf("111111\n");
break;
default:
break;
}
0x00384CF4 ba 4c 38 00 9c 4c 38 00
0x00384CFC ab 4c 38 00 8d 4c 38 00值较大时是否生成大表:case数值较大时依然会生成大表。
switch (101)
{
case 101:
printf("101\n");
break;
case 102:
printf("102\n");
break;
case 103:
printf("103\n");
break;
case 104:
printf("104\n");
break;
case 105:
printf("105\n");
break;
case 106:
printf("106\n");
break;
case 107:
printf("107\n");
break;
case 108:
printf("108\n");
break;
case 109:
printf("109\n");
break;
default:
break;
}
00F94C5E mov dword ptr [ebp-0C4h],65h
00F94C68 mov eax,dword ptr [ebp-0C4h]
00F94C6E sub eax,65h
00F94C71 mov dword ptr [ebp-0C4h],eax
00F94C77 cmp dword ptr [ebp-0C4h],8
00F94C7E ja $LN12+0Dh (0F94D16h)
00F94C84 mov ecx,dword ptr [ebp-0C4h]
00F94C8A jmp dword ptr [ecx*4+0F94D44h]保留最值,去掉两个case,就会发现空缺的case值在表中就会给出default的地址。
如果给出的是101~109之间空缺的值的话就会跳转到表中给出的default的地址;
如果是大于最大值的就会在和最大值比较的时候pass掉;
如果小于最小值的时候减去一个101~109的最小值时也会跳到default,因为ja是无符号比较。switch (101)
{
case 101:
printf("101\n");
break;
case 104:
printf("104\n");
break;
case 105:
printf("105\n");
break;
case 106:
printf("106\n");
break;
case 107:
printf("107\n");
break;
case 108:
printf("108\n");
break;
case 109:
printf("109\n");
break;
default:
break;
}
00134C5E mov dword ptr [ebp-0C4h],65h
00134C68 mov eax,dword ptr [ebp-0C4h]
00134C6E sub eax,65h
00134C71 mov dword ptr [ebp-0C4h],eax
00134C77 cmp dword ptr [ebp-0C4h],8
00134C7E ja $LN10+0Dh (0134CF4h)
00134C80 mov ecx,dword ptr [ebp-0C4h]
00134C86 jmp dword ptr [ecx*4+134D24h]0x00134D24 8d 4c 13 00 f4 4c 13 00
0x00134D2C f4 4c 13 00 9c 4c 13 00
0x00134D34 ab 4c 13 00 ba 4c 13 00
0x00134D3C c9 4c 13 00 d8 4c 13 00
0x00134D44 e7 4c 13 00 cc cc cc cc何时生成小表:case值连续但有些间隔时。使用小表来记录大表的偏移量。但是小表最多也只能记录FF个偏移量。
大表只列出有效的case和放在最后的default,而小表则列出所有case与间隔,case保持在大表中的偏移,间隔则给出在大表中default的偏移,即下面内存图中显示的08,而且显而易见的是最后一个给出的值时07,也就是最后一个case的值。
大表一共8 + 1 = 9个有效地址。
小表一共44个偏移量。switch (101)
{
case 101:
printf("101\n");
break;
case 107:
printf("107\n");
break;
case 108:
printf("108\n");
break;
case 109:
printf("109\n");
break;
case 111:
printf("101\n");
break;
case 122:
printf("107\n");
break;
case 133:
printf("108\n");
break;
case 144:
printf("109\n");
break;
default:
break;
}
switch (101)
00764C5E mov dword ptr [ebp-0C4h],65h
00764C68 mov eax,dword ptr [ebp-0C4h]
00764C6E sub eax,65h
00764C71 mov dword ptr [ebp-0C4h],eax
00764C77 cmp dword ptr [ebp-0C4h],2Bh
00764C7E ja $LN11+0Dh (0764D0Eh)
00764C84 mov ecx,dword ptr [ebp-0C4h]
00764C8A movzx edx,byte ptr [ecx+764D60h]
00764C91 jmp dword ptr [edx*4+764D3Ch]0x00764D3C 98 4c 76 00 a7 4c 76 00
0x00764D44 b6 4c 76 00 c5 4c 76 00
0x00764D4C d4 4c 76 00 e3 4c 76 00
0x00764D54 f2 4c 76 00 01 4d 76 00
0x00764D5C 0e 4d 76 00 00 08 08 08
0x00764D64 08 08 01 02 03 08 04 08
0x00764D6C 08 08 08 08 08 08 08 08
0x00764D74 08 05 08 08 08 08 08 08
0x00764D7C 08 08 08 08 06 08 08 08
0x00764D84 08 08 08 08 08 08 08 07如果case后是忽大忽小毫不连续的值时,不做讨论。
switch (101)
{
case 101:
printf("101\n");
break;
case 1:
printf("107\n");
break;
case 108:
printf("108\n");
break;
case 2:
printf("109\n");
break;
case 111:
printf("101\n");
break;
case 1231:
printf("107\n");
break;
case 9999:
printf("108\n");
break;
case 10:
printf("109\n");
break;
default:
break;
}
switch (101)
00754C5E mov dword ptr [ebp-0C4h],65h
00754C68 cmp dword ptr [ebp-0C4h],6Ch
00754C6F jg main+6Ah (0754CAAh)
00754C71 cmp dword ptr [ebp-0C4h],6Ch
00754C78 je main+0ABh (0754CEBh)
00754C7A mov eax,dword ptr [ebp-0C4h]
00754C80 sub eax,1
00754C83 mov dword ptr [ebp-0C4h],eax
00754C89 cmp dword ptr [ebp-0C4h],64h
00754C90 ja $LN11+0Dh (0754D43h)
00754C96 mov ecx,dword ptr [ebp-0C4h]
00754C9C movzx edx,byte ptr [ecx+754D84h]
00754CA3 jmp dword ptr [edx*4+754D70h]
00754CAA cmp dword ptr [ebp-0C4h],6Fh
00754CB1 je main+0C9h (0754D09h)
00754CB3 cmp dword ptr [ebp-0C4h],4CFh
00754CBD je main+0D8h (0754D18h)
00754CBF cmp dword ptr [ebp-0C4h],270Fh
00754CC9 je main+0E7h (0754D27h)
00754CCB jmp $LN11+0Dh (0754D43h)
还没有评论,来说两句吧...