C++语言中引用机制的实现分析

C++语言中引用机制的实现分析

原文地址:http://blog.sina.com.cn/s/blog_6fd68d5f0100n5zy.html

一案例代码(VS2005 C++环境下调试)

#include <stdio.h>

int&  RefFun(int& n)//通过引用传递参数
{
	n++;
	return n;
}

int ValueFun(int n)//通过变量值传递参数
{
	n++;
	return n;
}

int main(int argc,char* argv[])
{
	int a=10;
	int& x=a;//引用变量初始化

	int* pInt=&a;//取普通变量的地址
	int* pref=&x;//取引用变量的地址(其实获取的并不是引用变量的地址,而是被引用变量a的地址)

	int& b=RefFun(a);//函数返回引用,并将引用的别名赋值给引用变量

	int c=RefFun(a);//函数返回引用,并将引用变量的值赋值给整数变量

	int d=ValueFun(a);//函数返回变量值,

	printf("a=%d,b=%d,c=%d\n",a,b,c);

	return 0;
}



二 对上面的Main函数反汇编代码分析

注:

1)以下是在VS2005下,使用C++工程进行调试(切换到反汇编模式)显示的代码;

2)每行源代码下面为其对应的汇编代码;

3)读者也可以在自己的VS2005开发平台下进行反汇编分析!

反汇编分析代码如下:

int main(int argc,char* argv[])
{
00411430  push        ebp  
00411431  mov         ebp,esp 
00411433  sub         esp,114h 
00411439  push        ebx  
0041143A  push        esi  
0041143B  push        edi  
0041143C  lea         edi,[ebp-114h] 
00411442  mov         ecx,45h 
00411447  mov         eax,0CCCCCCCCh 
0041144C  rep stos    dword ptr es:[edi] 

	int a=10;
//对应的汇编代码:立即数寻址,给变量a赋值10,注意:dwordptr[a]为变量a的地址
0041144E  mov         dword ptr [a],0Ah 

	int& x=a;//引用变量初始化:其实质就是保存变量a的地址值到引用变量的内存单元!
00411455  lea         eax,[a] 
00411458  mov         dword ptr [x],eax 

	int* pInt=&a;//取普通变量的地址
0041145B  lea         eax,[a] //[a]表示变量a的地址;
0041145E  mov         dword ptr [pInt],eax //变量a的地址保存到指针变量pInt中:这也是指针变量的原理;

//下面的代码取引用变量的地址值,在实际很少用到该方式,在这里仅用于案例说明
	int* pref=&x;//取引用变量的地址(其实获取的并不是引用变量的地址,而是被引用变量a的地址)
00411461  mov         eax,dword ptr [x] //取引用变量内存单元保存的值(不是引用变量地址)
00411464  mov         dword ptr [pref],eax //引用变量内存单元值保存到指针变量;

//对上面两行源代码的汇编分析补充:

//1[x]表示引用变量x内存单元地址,dwordptr[x]:表示内存单元X保存的值(实际是一个地址值,实际指向被引用的变量a的值);

//2)引用变量的实现秘密:引用变量在内部实现其实就是一个常量指针变量;

//3)分析上面取普通变量地址,与取引用的地址内部实现机理是不一样的;

	int& b=RefFun(a);//函数返回引用,并将引用的别名赋值给引用变量
00411467  lea         eax,[a] //取变量a地址到EAX
0041146A  push        eax //变量a的地址为:0x411159h
0041146B  call        RefFun (411159h) //引用传递变量地址(指针)--引用实现的内部秘密!
00411470  add         esp,4 
00411473  mov         dword ptr [b],eax //EAX返回的为变量a的地址:实际为变量a的地址(初始化引用变量b)

	int c=RefFun(a);//函数返回引用,并将引用变量的值赋值给整数变量
00411476  lea         eax,[a] 
00411479  push        eax  //变量a的地址入栈(传递给函数的引用参数实际是变量的地址)
0041147A  call        RefFun (411159h) 
0041147F  add         esp,4 
00411482  mov         ecx,dword ptr [eax] 
00411484  mov         dword ptr [c],ecx 

	int d=ValueFun(a);//函数返回变量值,
00411487  mov         eax,dword ptr [a] //取变量a的值送到EAX寄存器
0041148A  push        eax  //变量a的值入栈(传递给函数:ValueFun);
0041148B  call        ValueFun (4110DCh) 
00411490  add         esp,4 
00411493  mov         dword ptr [d],eax 

	printf("a=%d,b=%d,c=%d\n",a,b,c);
00411496  mov         esi,esp 
00411498  mov         eax,dword ptr [c] 
0041149B  push        eax  
0041149C  mov         ecx,dword ptr [b] 
0041149F  mov         edx,dword ptr [ecx] 
004114A1  push        edx  
004114A2  mov         eax,dword ptr [a] 
004114A5  push        eax  
004114A6  push        offset string "a=%d,b=%d,c=%d\n" (41563Ch) 
004114AB  call        dword ptr [__imp__printf (4182B8h)] 
004114B1  add         esp,10h 
004114B4  cmp         esi,esp 
004114B6  call        @ILT+305(__RTC_CheckEsp) (411136h) 

	return 0;
004114BB  xor         eax,eax 
}

三代码实现分析---变量值传递参数&引用传递参数的区别

1对上面案例代码引用传递参数的RefFun分析--反汇编分析
int&  RefFun(int& n)//通过引用传递参数
{
004113A0  push        ebp  
004113A1  mov         ebp,esp 
004113A3  sub         esp,0C0h 
004113A9  push        ebx  
004113AA  push        esi  
004113AB  push        edi  
004113AC  lea         edi,[ebp-0C0h] 
004113B2  mov         ecx,30h 
004113B7  mov         eax,0CCCCCCCCh 
004113BC  rep stos    dword ptr es:[edi] 

	n++;//简单的一个加1对应5行汇编代码(下面的传值函数,只有3行,这是区别所在)
	//下面为对应的汇编代码,注意与下面函数ValueFun通过变量值传递参数的方式区别:
004113BE  mov         eax,dword ptr [n] //eax保存传递过来引用变量的地址值
004113C1  mov         ecx,dword ptr [eax] //取到传递过来的变量值
004113C3  add         ecx,1 
004113C6  mov         edx,dword ptr [n] //引用变量的地址保存到EDX
004113C9  mov         dword ptr [edx],ecx //保存加1后的结果;

return n;//由于变量n保存的为变量的地址,因此这里返回的是传递进来的地址值(区别于传值)
004113CB  mov         eax,dword ptr [n] 
}

2对上面案例代码引用传递参数的ValueFun分析--反汇编分析
int ValueFun(int n)//通过变量值传递参数
{
004113F0  push        ebp  
004113F1  mov         ebp,esp 
004113F3  sub         esp,0C0h 
004113F9  push        ebx  
004113FA  push        esi  
004113FB  push        edi  
004113FC  lea         edi,[ebp-0C0h] 
00411402  mov         ecx,30h 
00411407  mov         eax,0CCCCCCCCh 
0041140C  rep stos    dword ptr es:[edi] 

	n++;//对应的汇编代码(只有3行汇编代码,比上面的引用传递参数,相对简单):
0041140E  mov         eax,dword ptr [n] //dwordptr[n]为栈上的临时变量n的地址;
00411411  add         eax,1 
00411414  mov         dword ptr [n],eax 

	return n;//对应的汇编代码:返回的是栈上变量的值(这一点区别于引用,引用返回地址)
00411417  mov         eax,dword ptr [n] 
}

四 引用的实现秘密

通过对上面二,三章代码的反汇编代码的实现分析,对于引用变量的内部实现,可以得出如下结论:
1)引用的内部实现为相当于一个指针变量,与指针的实现方式类似;
2
用变量内存单元保存的指向变量地址(初始化时赋值,与指针不同地方时,引用变量在定义时必初始化,而且使用过程中,引用变量保存的内存单元地址值是不改变的这一点通过编译器来实现保证);
3
引用也可以进行取地址操作,但是取地址操作返回的不是引用变量所在的内存单元地址,而是被引用变量本身所在的内存单元地址
4
)引用的使用,在源代码级相当于普通的变量一样使用,但在函数参数传递引用变量时,内部传递的实际是变量的地址值(这种机制的实现是通过编译器(编译手段)来实现的)。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值