先贴代码再分析好了,VC2005 Release, 禁用优化,OllyDBG分析。
#include <stdio.h>
int inc0(int a, int b)
{
a = a + b;
return a;
}
int inc1(int& a, int b)
{
a = a + b;
return a;
}
int& inc2(int& a, int b)
{
a = a + b;
return a;
}
int inc3(int* a, int b)
{
*a = *a + b;
return *a;
}
int* inc4(int* a, int b)
{
*a = *a + b;
return a;
}
int main()
{
int a = 1;
inc0(a, 2);
inc1(a, 2);
inc2(a, 2);
inc3(&a, 2);
inc4(&a, 2);
return 0;
}
004017D0 /$ 55 push ebp
004017D1 |. 8BEC mov ebp, esp
004017D3 |. 51 push ecx
004017D4 |. C745 FC 01000>mov dword ptr [ebp-4], 1
004017DB |. 6A 02 push 2 ; /Arg2 = 00000002
004017DD |. 8B45 FC
mov eax, dword ptr [ebp-4] ; |
004017E0 |. 50 push eax ; |Arg1
004017E1 |. E8 CAFFFFFF call 004017B0 ; \Test01.004017B0
004017E6 |. 83C4 08 add esp, 8
004017E9 |. 6A 02 push 2 ; /Arg2 = 00000002
004017EB |. 8D4D FC
lea ecx, dword ptr [ebp-4] ; |
004017EE |. 51 push ecx ; |Arg1
004017EF |. E8 9CFFFFFF call 00401790 ; \Test01.00401790
004017F4 |. 83C4 08 add esp, 8
004017F7 |. 6A 02 push 2 ; /Arg2 = 00000002
004017F9 |. 8D55 FC
lea edx, dword ptr [ebp-4] ; |
004017FC |. 52 push edx ; |Arg1
004017FD |. E8 6EFFFFFF call 00401770 ; \Test01.00401770
00401802 |. 83C4 08 add esp, 8
00401805 |. 6A 02 push 2 ; /Arg2 = 00000002
00401807 |. 8D45 FC
lea eax, dword ptr [ebp-4] ; |
0040180A |. 50 push eax ; |Arg1
0040180B |. E8 40FFFFFF call 00401750 ; \Test01.00401750
00401810 |. 83C4 08 add esp, 8
00401813 |. 6A 02 push 2 ; /Arg2 = 00000002
00401815 |. 8D4D FC
lea ecx, dword ptr [ebp-4] ; |
00401818 |. 51 push ecx ; |Arg1
00401819 |. E8 12FFFFFF call 00401730 ; \Test01.00401730
0040181E |. 83C4 08 add esp, 8
00401821 |. 33C0 xor eax, eax
00401823 |. 8BE5 mov esp, ebp
00401825 |. 5D pop ebp
00401826 \. C3 retn
004017B0 /$ 55 push ebp ; int inc0(int a, int b)
004017B1 |. 8BEC mov ebp, esp
004017B3 |. 8B45 08 mov eax, dword ptr [ebp+8]
004017B6 |. 0345 0C add eax, dword ptr [ebp+C]
004017B9 |. 8945 08 mov dword ptr [ebp+8], eax
004017BC |. 8B45 08
mov eax, dword ptr [ebp+8]
004017BF |. 5D pop ebp
004017C0 \. C3 retn
00401790 /$ 55 push ebp ; int inc1(int& a, int b)
00401791 |. 8BEC mov ebp, esp
00401793 |. 8B45 08 mov eax, dword ptr [ebp+8]
00401796 |. 8B08 mov ecx, dword ptr [eax]
00401798 |. 034D 0C add ecx, dword ptr [ebp+C]
0040179B |. 8B55 08 mov edx, dword ptr [ebp+8]
0040179E |. 890A mov dword ptr [edx], ecx
004017A0 |. 8B45 08
mov eax, dword ptr [ebp+8]
004017A3 |. 8B00
mov eax, dword ptr [eax]
004017A5 |. 5D pop ebp
004017A6 \. C3 retn
00401770 /$ 55 push ebp ; int& inc2(int& a, int b)
00401771 |. 8BEC mov ebp, esp
00401773 |. 8B45 08 mov eax, dword ptr [ebp+8]
00401776 |. 8B08 mov ecx, dword ptr [eax]
00401778 |. 034D 0C add ecx, dword ptr [ebp+C]
0040177B |. 8B55 08 mov edx, dword ptr [ebp+8]
0040177E |. 890A mov dword ptr [edx], ecx
00401780 |. 8B45 08
mov eax, dword ptr [ebp+8]
00401783 |. 5D pop ebp
00401784 \. C3 retn
00401750 /$ 55 push ebp ; int inc3(int* a, int b)
00401751 |. 8BEC mov ebp, esp
00401753 |. 8B45 08 mov eax, dword ptr [ebp+8]
00401756 |. 8B08 mov ecx, dword ptr [eax]
00401758 |. 034D 0C add ecx, dword ptr [ebp+C]
0040175B |. 8B55 08 mov edx, dword ptr [ebp+8]
0040175E |. 890A mov dword ptr [edx], ecx
00401760 |. 8B45 08
mov eax, dword ptr [ebp+8]
00401763 |. 8B00
mov eax, dword ptr [eax]
00401765 |. 5D pop ebp
00401766 \. C3 retn
00401730 /$ 55 push ebp ; int* inc4(int* a, int b)
00401731 |. 8BEC mov ebp, esp
00401733 |. 8B45 08 mov eax, dword ptr [ebp+8]
00401736 |. 8B08 mov ecx, dword ptr [eax]
00401738 |. 034D 0C add ecx, dword ptr [ebp+C]
0040173B |. 8B55 08 mov edx, dword ptr [ebp+8]
0040173E |. 890A mov dword ptr [edx], ecx
00401740 |. 8B45 08
mov eax, dword ptr [ebp+8]
00401743 |. 5D pop ebp
00401744 \. C3 retn
从上面可以看出 inc0 传入的是数值,返回的也是数值,函数里面不能改变外面的值。
inc1,2,3,4 传入的都是指针,在函数内可以改变外面的变量的值。inc1 和 inc3 返回的都是数值,inc2 和 inc4 返回的都是指针。inc1 和 inc3 基本上没有区别,inc2 和 inc4 基本上也没有区别。 从高级语言上看(比如C++),&a 和 *a 都可以起到将函数内外的变量联系起来的作用,无论改函数里面还是外面的变量,改的都是同一个地址的值。
&a 的定义方法感觉更直观一些,因为只要函数的参数名字,和传进来变量名字一样,别人阅读程序的时候也很容易理解指的是同一个变量。用起来也很方便,不用像指针那样,还要加*才能取变量的值。
*a 的定义方法随便一本编程书上都会讲,相对来说大家理解更深刻吧。
所以两种定义方法各有个的好处,不过使用的时候,要注意函数是怎么定义的,传递参数的时候配套使用就行了。
还有,inc1(1,2) 这样的写法是不对的。因为根据 inc1 的定义,这里需要传入的是一个变量(从汇编的角度来看这里需要的是一个变量的地址),而这里的 1 和 2 一样都是常数,一定要事先定义变量再传入才可以。 就好像我们能用 i++, 但是不能用 2++, 3++ 一样。
以上纯属个人理解,欢迎指正。