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

来源:互联网 发布:h5免费制作网站 知乎 编辑:程序博客网 时间:2024/05/20 21:57

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地址到EAX0041146A  push        eax //变量a的地址为:0x411159h0041146B  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] //引用变量的地址保存到EDX004113C9  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
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 寄快递写错地址但已经发货了怎么办 拼多多发货时快递公司写错了怎么办 千牛发货信息写错了怎么办 发货物流单电话写错了怎么办 顺丰寄电脑保价后电脑进水了怎么办 微销通分享小程序没有二维码怎么办 京东的东西退掉但是赠品怎么办 买手机7天不给退换怎么办 买的水果拒收了商家不退钱怎么办 京东第三方签收后退货怎么办 京东上买的第三方的鞋子退货怎么办 淘宝买家退货条码不符签收了怎么办 此苹果已丢失并被抹掉怎么办 苹果手机显示已丢失并被抹掉怎么办 手机在保修期内坏了售后拖延怎么办 微信图片在电脑上打印不清楚怎么办 遇到职业搞坏淘宝店铺的买家怎么办 眼破裂伤无光感半个月怎么办 出了虫的豆豆熬稀饭喝了怎么办? 果汁阳台月季叶子掉光了怎么办 近看好看远看难看该怎么办 衣服褶皱没有熨斗的情况下怎么办 裤子磨得发亮怎么办也没有电熨斗 老是在灯箱拍照对眼睛不好怎么办 电信光纤宽带账号密码忘记了怎么办 遇到尴尬的事情自己缓不过来怎么办 注销微信账号显示非法请求怎么办 微信备份以前的被覆盖了怎么办 之前微信号被新微信号覆盖了怎么办 微信发出的消息变成绿色怎么办 收了客户的资金被骗走了怎么办 淘宝退回去的衣服店家不接收怎么办 淘宝同款衣服价格相差很大该怎么办 淘宝买的衣服退回去了不退钱怎么办 淘宝客人退回的衣服有口红印怎么办 淘宝拍产品照片被投诉著作权怎么办 员工总在节假日忙的时候请假怎么办 买东西商家少给了货应该怎么办 买家退回的衣服有污渍卖家该怎么办 商家说衣服有污渍不退怎么办 退回商家换货不给寄应怎么办