C++引用探索

来源:互联网 发布:sap系统优缺点知乎 编辑:程序博客网 时间:2024/06/06 07:05

   c++引用实质上就是指针(用的是VC6.0其它编译器可能不一样)。

一.作为函数的形参

#include <iostream>using namespace std;int fun(int &a,int &b,int &c){return a+b+c;}int main(void){int a=1;int b=2;int c=3;int e=fun(a,b,c);cout<<e<<endl;return 1;}


首先时定义了a,b,c三个变量的汇编如下:(ebp为栈底寄存器,esp为栈顶寄存器,eax为通用寄存器就像c++普通变量一样

int a=1;  mov         dword ptr [ebp-4],1  //将1存储在ebp-4的内存单元int b=2; mov         dword ptr [ebp-8],2//将1存储在ebp-8的内存单元int c=3; mov         dword ptr [ebp-0Ch],3//将1存储在ebp-12的内存单元
int e=fun(a,b,c);//看看c++一句话汇编要这么多呵呵lea         eax,[ebp-0Ch]//取ebp-12内存单元的地址,将该地址值存放在eax里        3push        eax       //将eax的值也就是ebp-12的地址压栈lea         ecx,[ebp-8]//同上2push        ecx//同上lea         edx,[ebp-4]//同上1push        edx//同上call        @ILT+380(fun) (00401181)最后调用fun函数

写到这里好像还是不知道要表达什么?不要着急从上面我们可以得到如下结论:

通过编译器编译得知fun三个参数是引用,会将实参的地址push到main函数栈的顶端(说是顶端其实也是相对的,这里的顶端是指push的方向。有的可能从高地址使用到地地址,有的可能是从地地址使用到高地址,其实这不是主要的)。这样使esp寄存器就保存了指向保存ebp-4单元的地址(也就是保存1的内存单元地址)的内存单元的地址。(其实也就是所谓的esp指向了内存单元m1 ,而m1就保存了,内存单元m2的地址)。

好了,我们先进入fun函数的内部进行查看。

以下是fun函数内部的重要准备工作的汇编

 push        ebp//首先将ebp的值保存压栈,这起到保护现场,等fun函数完了有句这样的pop edp这样是edp又恢复到进去fun函数之前的值了。(这就牵涉到函数中断等相关问题了这里不做表述)  mov         ebp,esp
 sub         esp,40h//移动esp栈顶指针,为局部变量和预留空间的内存单元做准备
return a+b+c; mov         eax,dword ptr [ebp+8]//相当于eax=edp+8,此时eax也就等于main函数 实参 a的地址 mov         eax,dword ptr [eax]//从通过地址得到eax的值,也就是1 mov         ecx,dword ptr [ebp+0Ch]//同上 add         eax,dword ptr [ecx]//将ecx保存的内存里面的值与eax相加,相当于eax=eax+*ecx   mov         edx,dword ptr [ebp+10h]   add         eax,dword ptr [edx]

从fun函数汇编看出,fun函数访问的形参引用的值是保存的main函数里面的,然后通过ebp栈底寄存器内存偏移,可以访问到a,b,c的值了。因为调用与被调用的函数是处在一段连续的内存块,通过逻辑栈将其分开。

二.局部变量的引用

int a=1;
 int& b=a;

如以上语句,汇编如下。

int a=1;mov         dword ptr [ebp-4],1//这就不解释了int& b=a; lea         eax,[ebp-4]//值也是去ebp-4内存单元的地址,放到eax   mov         dword ptr [ebp-8],eax//将eax的值放在ebp-8内存单元里
cout<<b;
mov         ecx,dword ptr [ebp-8]mov         edx,dword ptr [ecx]//这也是首先访问ebp-8内存单元里面所存的地址,然后通过地址得到改地址里的值。

比较简单,但也有个特殊之处就是因为b在这里也是局部变量所以也放在了函数开辟好的预留空间里。通常预留空间的大小为40h+sizeof(class)*sum。class为类型,sum为函数局部变量的个数。

引用的使用就不完全列举了,下面列举下指针,随便与引用做个比较。

同样一段这样的代码我把它改成指针

 int a=1;
 int *b=&a;

汇编如下:

int a=1;
mov         dword ptr [ebp-4],1
 int *b=&a;
 lea         eax,[ebp-4]
 mov         dword ptr [ebp-8],eax
瞧瞧简直一模一样,至少在VC6.0是这样处理的。这可不是我故意这样做的,事实就是如此。

这就充分说明对引用实际上与指针没什么不同,但C++为什么还要把扩展引用这个功能呢?

我想既然它叫c++那么c里面有的它必须有,c里面没有的它也要有不然怎么++呢?

不存在空的引用,引用必须初始化。等等这些都可以在编译期帮我们把危险降低。而指针就没有这个限制,有时一个空的指针,或者没有初始化而使用的指针都是造成软件崩溃的原因,所以使用指针你必须很小心。还是应该多使用引用啊。

但不要使用这样的引用

int a;

int &b=a;

或者

int &b=fun();

这样会使引用到一些不确定的内存里面去。

 



 

原创粉丝点击