C基础反汇编

本文探讨了C语言switch语句在性能上的优势,特别是在case值连续时如何生成大表以提高效率。当case值较少或不连续时,编译器可能采用类似if的逐个比较。大表的生成不受case值顺序影响,并且在值较大时仍会被使用。小表用于记录大表的偏移量,当case值有间隔时。对于不连续的case值情况,文章并未深入讨论。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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]  

1. 什么时候会生成大表: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)  

2. 顺序不会影响生成大表:观察内存可以发现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

3. 值较大时是否生成大表: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]  

4. 保留最值,去掉两个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

5. 何时生成小表: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

6. 如果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) 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值