给出一个很简单的引用实例C++源码:
#include<iostream>
using namespace std;
void Add(int& __nVar)
{
__nVar++;
}
void main()
{
int nVar=0x00000001;
Add(nVar);
cout<<"nVar="<<nVar<<endl;
}
运行结果:nVar=2
下面是反汇编代码:
5: void Add(int& __nVar)
6: {
00401580 55 push ebp
00401581 8B EC mov ebp,esp
00401583 83 EC 40 sub esp,40h
00401586 53 push ebx
00401587 56 push esi
00401588 57 push edi
00401589 8D 7D C0 lea edi,[ebp-40h]
0040158C B9 10 00 00 00 mov ecx,10h
00401591 B8 CC CC CC CC mov eax,0CCCCCCCCh
00401596 F3 AB rep stos dword ptr [edi]//以上为DEBUG模式标准子函数内部初始代码;
7: __nVar++;
00401598 8B 45 08 mov eax,dword ptr [ebp+8]//将参数复制到 EAX;参数的内容其实是32位的地址;
0040159B 8B 08 mov ecx,dword ptr [eax]//将参数内容的地址所指向的DWORD类型数据复制到ECX;
0040159D 83 C1 01 add ecx,1//ECX内容加1;
004015A0 8B 55 08 mov edx,dword ptr [ebp+8]//将参数复制到 EDX;参数的内容其实是32位的地址;
004015A3 89 0A mov dword ptr [edx],ecx//将ECX的内容复制到参数内容的地址所指向的DWORD类型数据;
8: }
004015A5 5F pop edi
004015A6 5E pop esi
004015A7 5B pop ebx
004015A8 8B E5 mov esp,ebp
004015AA 5D pop ebp
004015AB C3 ret//DEBUG模式子函数返回代码;恢复现场;
10: void main()
11: {
004015C0 55 push ebp
004015C1 8B EC mov ebp,esp
004015C3 83 EC 44 sub esp,44h
004015C6 53 push ebx
004015C7 56 push esi
004015C8 57 push edi
004015C9 8D 7D BC lea edi,[ebp-44h]
004015CC B9 11 00 00 00 mov ecx,11h
004015D1 B8 CC CC CC CC mov eax,0CCCCCCCCh
004015D6 F3 AB rep stos dword ptr [edi]//以上为DEBUG模式标准子函数内部初始代码;注意main()对编译器而言仍然是子函数;
并不是入口函数;
12: int nVar=0x00000001;
004015D8 C7 45 FC 01 00 00 00 mov dword ptr [ebp-4],1//将0x00000001赋值给nVar;
13: Add(nVar);
004015DF 8D 45 FC lea eax,[ebp-4]//得到nVar的偏移地址
004015E2 50 push eax//EAX作为实际参数提供给Add()函数
004015E3 E8 52 FC FF FF call @ILT+565(Add) (0040123a)//通过ILT表调用Add函数;
004015E8 83 C4 04 add esp,4//恢复栈顶指针;因为前面的PUSH EAX;
14: cout<<"nVar="<<nVar<<endl;
//打印函数不做反汇编解释;
004015EB 68 C8 10 40 00 push offset @ILT+195(std::endl) (004010c8)
004015F0 8B 4D FC mov ecx,dword ptr [ebp-4]
004015F3 51 push ecx
004015F4 68 1C E0 46 00 push offset string "nVar=" (0046e01c)
004015F9 68 90 BE 47 00 push offset std::cout (0047be90)
004015FE E8 87 FC FF FF call @ILT+645(std::operator<<) (0040128a)
00401603 83 C4 08 add esp,8
00401606 8B C8 mov ecx,eax
00401608 E8 F2 FA FF FF call @ILT+250(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010ff)
0040160D 8B C8 mov ecx,eax
0040160F E8 CC FB FF FF call @ILT+475(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e0)
15: }
//此处省略掉main()函数返回代码;
总结:从主函数main()的对Add函数的调用处可以看出,EAX作为实际参数入栈;EAX的内容为变量nVar的偏移地址;这一点非常
重要;
再回过头去看Add函数体内,提到2次的“参数内容的地址所指向的DWORD类型”其实就是EAX的内容;即nVar的偏移地址;
因此可以看出,在Add函数体内,有权限对变量nVar进行操作;比如+1;因为参数EAX将nVar的偏移地址传递给了Add函数,Add函数
就可以通过这个偏移地址去改动此地址的内容;
因此,对于代码:Add(nVar);我们知道传递的其实是nVar的偏移地址;对于引用的作用也就一目了然了;