重学C---------第三节:求两个整数中的大者
子函数,就像小弟一样,帮我做各种各样的事
1 #include <stdio.h> 2 3 void main() 4 { 5 int max(int x,int y); //函数的声明 6 int a,b,c; 7 scanf("%d,%d",&a,&b); //获取输入 8 c=max(a,b); //调用子函数 9 printf("max= %d \n",c); 10 } 11 12 int max(int x,int y) 13 { 14 int z; 15 if(x>y) 16 { 17 z=x; 18 } 19 else 20 { 21 z=y; 22 } 23 return z; 24 }
虽然这个程序有更好的方法,但我们的目标不是优化这个程序,所以。。。
老样子,用OD查看Debug版,当然先看主函数:
1 00401020 >/> \55 push ebp 2 00401021 |. 8BEC mov ebp, esp 3 00401023 |. 83EC 4C sub esp, 4C 4 00401026 |. 53 push ebx 5 00401027 |. 56 push esi 6 00401028 |. 57 push edi 7 00401029 |. 8D7D B4 lea edi, dword ptr [ebp-4C] 8 0040102C |. B9 13000000 mov ecx, 13 9 00401031 |. B8 CCCCCCCC mov eax, CCCCCCCC 10 00401036 |. F3:AB rep stos dword ptr es:[edi] 11 00401038 |. 8D45 F8 lea eax, dword ptr [ebp-8] 12 0040103B |. 50 push eax 13 0040103C |. 8D4D FC lea ecx, dword ptr [ebp-4] 14 0040103F |. 51 push ecx 15 00401040 |. 68 28504200 push 00425028 ; /format = "%d,%d" 16 00401045 |. E8 26010000 call scanf ; \scanf 17 0040104A |. 83C4 0C add esp, 0C 18 0040104D |. 8B55 F8 mov edx, dword ptr [ebp-8] 19 00401050 |. 52 push edx ;第二个参数 20 00401051 |. 8B45 FC mov eax, dword ptr [ebp-4] 21 00401054 |. 50 push eax ;第一个参数 22 00401055 |. E8 ABFFFFFF call 00401005 ;子函数的位置 23 0040105A |. 83C4 08 add esp, 8 24 0040105D |. 8945 F4 mov dword ptr [ebp-C], eax 25 00401060 |. 8B4D F4 mov ecx, dword ptr [ebp-C] 26 00401063 |. 51 push ecx ; /<%d> 27 00401064 |. 68 1C504200 push 0042501C ; |format = "max= %d ",LF,"" 28 00401069 |. E8 82000000 call printf ; \printf 29 0040106E |. 83C4 08 add esp, 8 30 00401071 |. 5F pop edi 31 00401072 |. 5E pop esi 32 00401073 |. 5B pop ebx 33 00401074 |. 83C4 4C add esp, 4C 34 00401077 |. 3BEC cmp ebp, esp 35 00401079 |. E8 52010000 call _chkesp 36 0040107E |. 8BE5 mov esp, ebp 37 00401080 |. 5D pop ebp 38 00401081 \. C3 retn
我们继续看子函数:
1 004010A0 >/> \55 push ebp 2 004010A1 |. 8BEC mov ebp, esp 3 004010A3 |. 83EC 44 sub esp, 44 4 004010A6 |. 53 push ebx 5 004010A7 |. 56 push esi 6 004010A8 |. 57 push edi 7 004010A9 |. 8D7D BC lea edi, dword ptr [ebp-44] 8 004010AC |. B9 11000000 mov ecx, 11 9 004010B1 |. B8 CCCCCCCC mov eax, CCCCCCCC 10 004010B6 |. F3:AB rep stos dword ptr es:[edi] 11 004010B8 |. 8B45 08 mov eax, dword ptr [ebp+8] ; 第一个实参 12 004010BB |. 3B45 0C cmp eax, dword ptr [ebp+C] ; 与第二个实参比较 13 004010BE |. 7E 08 jle short 004010C8 ; 如果小于等于则跳 14 004010C0 |. 8B4D 08 mov ecx, dword ptr [ebp+8] 15 004010C3 |. 894D FC mov dword ptr [ebp-4], ecx 16 004010C6 |. EB 06 jmp short 004010CE 17 004010C8 |> 8B55 0C mov edx, dword ptr [ebp+C] 18 004010CB |. 8955 FC mov dword ptr [ebp-4], edx 19 004010CE |> 8B45 FC mov eax, dword ptr [ebp-4] 20 004010D1 |. 5F pop edi 21 004010D2 |. 5E pop esi 22 004010D3 |. 5B pop ebx 23 004010D4 |. 8BE5 mov esp, ebp 24 004010D6 |. 5D pop ebp 25 004010D7 \. C3 retn
下面用IDA来瞅瞅,首先是主函数
1 int __cdecl main() 2 { 3 char v1; // [sp+Ch] [bp-4Ch]@1 4 int v2; // [sp+4Ch] [bp-Ch]@1 5 int v3; // [sp+50h] [bp-8h]@1 6 int v4; // [sp+54h] [bp-4h]@1 7 8 memset(&v1, 0xCCCCCCCCu, 0x4Cu); 9 scanf("%d,%d", (unsigned int)&v4); 10 v2 = j_max(v4, v3); 11 printf("max= %d \n", v2); 12 return _chkesp(); 13 }
然后是子函数:
1 int __cdecl max(int a1, int a2) 2 { 3 char v3; // [sp+Ch] [bp-44h]@1 4 int v4; // [sp+4Ch] [bp-4h]@2 5 6 memset(&v3, -858993460, 0x44u); 7 if ( a1 <= a2 ) 8 v4 = a2; 9 else 10 v4 = a1; 11 return v4; 12 }
我修改了下,变成
1 int __cdecl max(int x, int y) 2 { 3 char v3; // [sp+Ch] [bp-44h]@1 4 int z; // [sp+4Ch] [bp-4h]@2 5 6 memset(&v3, 0xCCCCCCCCu, 0x44u); 7 if ( x <= y ) 8 z = y; 9 else 10 z = x; 11 return z; 12 }
***************************************************************************************************************************
下面是Release版的分析
首先,OD主函数
1 00401000 /$ 83EC 08 sub esp, 8 2 00401003 |. 8D4424 00 lea eax, dword ptr [esp] 3 00401007 |. 8D4C24 04 lea ecx, dword ptr [esp+4] 4 0040100B |. 50 push eax 5 0040100C |. 51 push ecx 6 0040100D |. 68 3C804000 push 0040803C ; ASCII "%d,%d" 7 00401012 |. E8 6A000000 call 00401081 8 00401017 |. 8B5424 0C mov edx, dword ptr [esp+C] 9 0040101B |. 8B4424 10 mov eax, dword ptr [esp+10] 10 0040101F |. 52 push edx 11 00401020 |. 50 push eax 12 00401021 |. E8 1A000000 call 00401040 ; 子函数 13 00401026 |. 50 push eax 14 00401027 |. 68 30804000 push 00408030 ; ASCII "max= %d ",LF 15 0040102C |. E8 1F000000 call 00401050 16 00401031 |. 83C4 24 add esp, 24 17 00401034 \. C3 retn
然后,OD子函数
1 00401040 /$ 8B4424 04 mov eax, dword ptr [esp+4] 2 00401044 |. 8B4C24 08 mov ecx, dword ptr [esp+8] 3 00401048 |. 3BC1 cmp eax, ecx 4 0040104A |. 7F 02 jg short 0040104E 5 0040104C |. 8BC1 mov eax, ecx 6 0040104E \> C3 retn
看来经过优化,代码要比Debug版的少很多。
下面用IDA来看看是不是这样
1 int __cdecl main(int argc, const char **argv, const char **envp) 2 { 3 int v3; // eax@1 4 int v5; // [sp+0h] [bp-8h]@1 5 int v6; // [sp+4h] [bp-4h]@1 6 7 scanf("%d,%d", &v6, &v5); 8 v3 = sub_401040(v6, v5); 9 return sub_401050("max= %d \n", v3); 10 }
我修改下,变成
1 int __cdecl main(int argc, const char **argv, const char **envp) 2 { 3 int z; // eax@1 4 int y; // [sp+0h] [bp-8h]@1 5 int x; // [sp+4h] [bp-4h]@1 6 7 scanf("%d,%d", &x, &y); 8 z = max(x, y); 9 return printf("max= %d \n", z); 10 }
进入子函数瞅瞅:
1 int __cdecl max(int a1, int a2) 2 { 3 int result; // eax@1 4 5 result = a1; 6 if ( a1 <= a2 ) 7 result = a2; 8 return result; 9 }
我把它修改为:
1 int __cdecl max(int x, int y) 2 { 3 int result; // eax@1 4 5 result = x; 6 if ( x <= y ) 7 result = y; 8 return result; 9 }
工程下载地址:https://files.cnblogs.com/tk091/rl003.7z
=======================================2012-5-11===================================
1 ; int __cdecl main(int argc, const char **argv, const char **envp) 2 _main proc near 3 4 var_8= dword ptr -8 5 var_4= dword ptr -4 6 argc= dword ptr 4 7 argv= dword ptr 8 8 envp= dword ptr 0Ch 9 10 sub esp, 8 11 lea eax, [esp+8+var_8] 12 lea ecx, [esp+8+var_4] 13 push eax 14 push ecx 15 push offset Format ; "%d,%d" 16 call _scanf 17 mov edx, [esp+14h+var_8] 18 mov eax, [esp+14h+var_4] 19 push edx 20 push eax 21 call sub_401040 22 push eax 23 push offset aMaxD ; "max= %d \n" 24 call _printf 25 add esp, 24h 26 retn 27 _main endp
修改下临时变量,就变成了
1 ; int __cdecl main(int argc, const char **argv, const char **envp) 2 _main proc near 3 4 b= dword ptr -8 5 a= dword ptr -4 6 argc= dword ptr 4 7 argv= dword ptr 8 8 envp= dword ptr 0Ch 9 10 sub esp, 8 11 lea eax, [esp+8+b] 12 lea ecx, [esp+8+a] 13 push eax 14 push ecx 15 push offset Format ; "%d,%d" 16 call _scanf 17 mov edx, [esp+14h+b] 18 mov eax, [esp+14h+a] 19 push edx 20 push eax 21 call func_max 22 push eax 23 push offset aMaxD ; "max= %d \n" 24 call _printf 25 add esp, 24h 26 retn 27 _main endp
这样看起来就清晰多了。