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

来源:互联网 发布:高分三号 数据预处理 编辑:程序博客网 时间:2024/06/05 14:41
 

一案例代码(VS2010C++环境下调试)
#include"stdafx.h"
int&__stdcallRefFun(int&n)//
通过引用传递参数
{
n++;
returnn;
}

int__stdcallValueFun(intn)//
过变量值传递参数
{
n++;
returnn;
}

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

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

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

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

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


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

return0;
}

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

注:

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

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

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

反汇编分析代码如下:
intmain(intargc,char*argv[])
{
004295E0pushebp
004295E1movebp,esp
004295E3subesp,0F0h
004295E9pushebx
004295EApushesi
004295EBpushedi
004295ECleaedi,[ebp-0F0h]
004295F2movecx,3Ch
004295F7moveax,0CCCCCCCCh
004295FCrepstosdwordptres:[edi]

inta=10;
//
对应的汇编代码:立即数寻址,给变量a赋值10,注意:dwordptr[a]为变量a的地址;
004295FEmovdwordptr[a],0Ah

int&x=a;//
引用变量初始化:其实质就是保存变量a的地址值到引用变量的内存单元!
004272B5leaeax,[a]
004272B8movdwordptr[x],eax

int*pInt=&a;//
取普通变量的地址
004272BBleaeax,[a]//[a]
表示变量a的地址;
004272BEmovdwordptr[pInt],eax//
变量a的地址保存到指针变量pInt中:这也是指针变量的原理;

//下面的代码取引用变量的地址值,在实际很少用到该方式,在这里仅用于案例说明!
int*pref=&x;//
取引用变量地址
004272C1moveax,dwordptr[x]//
取引用变量内存单元保存的值(不是引用变量地址)
004272C4movdwordptr[pref],eax//引用变量内存单元值保存到指针变量;

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

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

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

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

int&b=RefFun(a);//
函数返回引用,并将引用的别名赋值给引用变量
//
对应的汇编代码:
00429605leaeax,[a]//
取变量a地址到EAX
00429608pusheax//
变量a的地址为:0x4260FEh
00429609callRefFun(4260FEh)//
引用传递变量地址(指针)--引用实现的内部秘密!
0042960Emovdwordptr[b],eax//EAX
返回的为变量a的地址:实际为变量a的地址(初始化引用变量b

intc=RefFun(a);//
函数返回引用,并将引用变量的值赋值给整数变量
//
上面代码对应的汇编代码:
00429611leaeax,[a]
00429614pusheax//
变量a的地址入栈(传递给函数的引用参数实际是变量的地址)
00429615callRefFun(4260FEh)
0042961Amovecx,dwordptr[eax]
0042961Cmovdwordptr[c],ecx

intd=ValueFun(a);

//
上面代码对应的汇编代码:
0042961Fmoveax,dwordptr[a]//
取变量a的值送到EAX寄存器
00429622pusheax//
变量a的值入栈(传递给函数:ValueFun);
00429623callValueFun(426103h)
00429628movdwordptr[d],eax
printf("a=%d,b=%d,c=%d\n",a,b,c);
0042962Bmoveax,dwordptr[c]
0042962Epusheax
0042962Fmovecx,dwordptr[b]
00429632movedx,dwordptr[ecx]
00429634pushedx
00429635moveax,dwordptr[a]
00429638pusheax
00429639pushoffsetstring"a=%d,b=%d,c=%d\n"(471C6Ch)
0042963Ecall@ILT+3875(_printf)(425F28h)
00429643addesp,10h

return0;
00429646xoreax,eax
}


三代码实现分析---变量值传递参数&引用传递参数的区别
1
对上面案例代码引用传递参数的RefFun分析--反汇编分析
int&__stdcallRefFun(int&n)//
引用传递参数
{
00429560pushebp
00429561movebp,esp
00429563subesp,0C0h
00429569pushebx
0042956Apushesi
0042956Bpushedi
0042956Cleaedi,[ebp-0C0h]
00429572movecx,30h
00429577moveax,0CCCCCCCCh
0042957Crepstosdwordptres:[edi]

n++;//
简单的一个加1对应5行汇编代码(下面的传值函数,只有3行,这是区别所在)
//
下面为对应的汇编代码,注意与下面函数ValueFun通过变量值传递参数的方式区别:

0042957Emoveax,dwordptr[n]//eax
保存传递过来引用变量的地址值
00429581movecx,dwordptr[eax]//
取到传递过来的变量值
00429583addecx,1
00429586movedx,dwordptr[n]//
引用变量的地址保存到EDX
00429589movdwordptr[edx],ecx//
保存加1后的结果;

returnn;//
由于变量n保存的为变量的地址,因此这里返回的是传递进来的地址值(区别于传值)
0042958Bmoveax,dwordptr[n]
}

2
对上面案例代码引用传递参数的ValueFun分析--反汇编分析
int__stdcallValueFun(intn)//
变量值传递参数

{
004295A0pushebp
004295A1movebp,esp
004295A3subesp,0C0h
004295A9pushebx
004295AApushesi
004295ABpushedi
004295ACleaedi,[ebp-0C0h]
004295B2movecx,30h
004295B7moveax,0CCCCCCCCh
004295BCrepstosdwordptres:[edi]

n++;//
对应的汇编代码(只有3行汇编代码,比上面的引用传递参数,相对简单):
004295BEmoveax,dwordptr[n]//dwordptr[n]
为栈上的临时变量n的地址;
004295C1addeax,1
004295C4movdwordptr[n],eax

returnn;
//
对应的汇编代码:返回的是栈上变量的值(这一点区别于引用,引用返回地址
004295C7moveax,dwordptr[n]
}

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

   不能将引用简单理解为变量的代记符号,引用本身是通过指针实现,并且占用相应的内存空间。

具体还可以参考:《c++语言引用变量实现机制浅析》,刘维富,南通工学院学报

五关于汇编语言的补充
1
学习掌握汇编语言的原理(注:这里是原理学习,不是学习使用汇编语言进行代码编写),对提高软件开发者程序分析,提高对计算机系统实现原理的理解(如堆,栈,函数运行分析,以及掌握操作系统的运行实现机制,包括栈的生长方向等理解),都是非常有帮助;

2
通过汇编分析,所有的实现机理都可以通过调试分析出来,对提高开发者的分析能力是非常有帮助的!包括对于C++的很多知识点,都可以通过反汇编分析,可以真正了解和掌握其背后的运行机理,提高对语言的正确运用;

原创粉丝点击