精华内容
下载资源
问答
  • 引用的本质
    万次阅读 多人点赞
    2015-07-08 16:33:22

    代码运行环境:Windows7 32bits+VS2017+Win32。


    引用是 C++ 引入的重要特性,它使原来在 C 中必须用指针实现的功能有了另一种实现的选择,在书写形式上更为简洁。那么引用的本质是什么,它与指针又有什么关系呢?

    1.引用的底层实现方式

    引用被称为变量的别名,它不能脱离被引用对象独立存在,这是在高级语言层面的概念和理解,并未揭示引用的实现方式。常见错误说法是“引用“自身不是一个变量,甚至编译器可以不为引用分配空间。

    实际上,引用本身是一个变量,只不过这个变量的定义和使用与普通变量有显著的不同。为了解引用变量底层实现机制,考查如下代码:

    int i = 5;
    int &ri = i;
    ri = 8;
    

    在Visual Studio 2017环境的debug模式调试代码,反汇编查看源码对应的汇编代码的步骤是:调试->窗口->反汇编,即可得到如下原码对应的汇编代码:

    int i=5;
    00A013DE  mov        dword ptr [i],5    	//将文字常量5送入变量i
    int &ri=i;
    00A013E5  lea        eax,[i]  	 	    	//将变量i的地址送入寄存器eax
    00A013E8  mov        dword ptr [ri],eax  	//将寄存器的内容(也就是变量i的地址)送入变量ri
    ri=8;
    00A013EB  mov        eax,dword ptr [ri]  	//将变量ri的值送入寄存器eax
    00A013EE  mov        dword ptr [eax],8   	//将数值8送入以eax的内容为地址的单元中
    return 0;
    00A013F4  xor        eax,eax
    

    在汇编代码中,ri 的数据类型为 dword。也就是说,ri 要在内存中占据 4 个字节的位置。所以,ri 的确是一个变量,它存放的是被引用对象的地址。

    通常情况下,地址是由指针变量存放的,那么指针变量和引用变量有什么区别呢?

    使用指针常量实现上面的代码功能。考查如下代码:

    int i = 5;
    int* const pi = &i;
    *pi = 8;
    

    按照相同的方式,在 VS2017 中得到如下汇编代码:

    int i=5;
    011F13DE  mov         dword ptr [i],5  
    int * const pi=&i;
    011F13E5  lea         eax,[i]  
    011F13E8  mov         dword ptr [pi],eax  
    *pi=8;
    011F13EB  mov         eax,dword ptr [pi]  
    011F13EE  mov         dword ptr [eax],8  
    

    观察以上代码可以看出:
    (1)只要将pi换成ri,所得汇编代码与第一段所对应的汇编代码完全一样。所以,引用变量在功能上等于一个指针常量,即一旦指向某一个单元就不能在指向别处。
    (2)在底层,引用变量由指针按照指针常量的方式实现。

    2.高级语言层面引用与指针常量的关系

    (1)在内存中都是占用4个字节(32bits系统中)的存储空间,存放的都是被引用对象的地址,都必须在定义的同时进行初始化。

    (2)指针常量本身(以p为例)允许寻址,即&p返回指针常量(常变量)本身的地址,被引用对象用*p表示;引用变量本身(以r为例)不允许寻址,&r返回的是被引用对象的地址,而不是变量r的地址(r的地址由编译器掌握,程序员无法直接对它进行存取),被引用对象直接用r表示。

    (3)凡是使用了引用变量的代码,都可以转换成使用指针常量的对应形式的代码,只不过书写形式上要繁琐一些。反过来,由于对引用变量使用方式上的限制,使用指针常量能够实现的功能,却不一定能够用引用来实现。

    例如,下面的代码是合法的:

    int i=5, j=6;
    int* const array[]={&i,&j};
    

    而如下代码是非法的:

    int i=5, j=6;
    int& array[]={i,j};
    

    也就是说,数组元素允许是指针常量,却不允许是引用。C++语言机制如此规定,原因是避免C++语法变得过于晦涩。假如定义一个“引用的数组”,那么array[0]=8;这条语句该如何理解?是将数组元素array[0]本身的值变成8呢,还是将array[0]所引用的对象的值变成8呢?对于程序员来说,这种解释上的二义性对正确编程是一种严重的威胁,毕竟程序员在编写程序的时候,不可能每次使用数组时都要回过头去检查数组的原始定义。

    3.改变引用指别的对象

    C++ 规定,引用变量在定义的时候就必须初始化,也即是将引用变量与被引用对象进行绑定。而这种引用关系一旦确定就不允许改变,直到引用变量结束其生命期。这种规定是在高级语言的层面上,由 C++ 编译器所做的检查来保障实施的。在特定的环境下,利用特殊的手段,还是可以在运行时动态地改变一个引用变量与被引用对象的对应关系,使引用变量指向一个别的对象。

    #include <iostream>
    using namespace std;
    
    int main(int argc,char* argv[]) {
    	int i=5,j=6;
    	int &r=i;
    	void *pi,*pj;
    	int* addr;
    	int dis;
    
    	pi=&i;    //取整型变量i的地址
    	pj=&j;    //取整型变量j的地址
    	dis=(int)pj-(int)pi;//计算连续两个整型变量的内存地址之间距离
    	addr=(int*)((int)pj+dis);//计算引用变量r在内存中的地址
    
    	cout<<"&i:"<<pi<<endl;
    	cout<<"&j:"<<pj<<endl;
    	cout<<"&pi:"<<&pi<<endl;
    	cout<<"&pj:"<<&pj<<endl;
    	cout<<"&addr:"<<&addr<<endl;
    	cout<<"&dis:"<<&dis<<endl;
    	cout<<"distance:"<<dis<<endl;
    	
    	(*addr)=(int)&j;    //将j的地址赋给引用r(此处把r看作指针)
    	
    	cout<<"addr:"<<addr<<endl;
    	r=100;
    	cout<<i<<" "<<j<<endl;
    	return 0;
    }
    
    

    这个程序在 Debug 模式下输出结果如下:

    &i:0038FC1C
    &j:0038FC10
    &pi:0038FBF8
    &pj:0038FBEC
    &addr:0038FBE0
    &dis:0038FBD4
    distance:-12
    addr:0038FC04
    5 100
    

    仔细观察代码和输出结果可以得出如下结论:

    (1)Win32(Windows 32bits)平台下,int 型变量和指针变量都占用 4 个字节,但是 &i-&j=-12 并非想象中的 4。
    一是局部变量存储在栈空间,栈在主存中的生长方向是从高地址到低地址,因此i和j的地址差为负数;
    二是 Debug 模式下,int 变量前后均添加 4 个字节的调试信息,故一个 int 占用了 12 字节。模式设为 Release,就会发现栈上连续定义的 int 变量,地址相差 4 个字节。

    (2)指针变量 pi 与 int 变量 j 地址间相差了 24 字节,按照推理,如果引用r不占用内存空间,那么地址差应该为 12 字节,这也说明了引用变量在内存占用空间。

    (3)将引用变量r理解成指针,间接的获取r的地址并修改 r 的值,使r指向变量 j。从引用的角度理解就是将引用 r 与 j 绑定。对 r 赋值,结果显示 j 的值被修改。

    以上代码较为诡异,实际编程绝不提倡大家模仿。利用以上程序可以看出“引用“本身的确是一个变量,它存放被引用对象的地址。并且,利用特殊手段能够找到这个引用变量的地址并修改其自身在内存中的值,从而实现与其他对象的绑定。

    这个程序在 VS 环境下的 Release 模式编译不通过,会出现内存访问冲突,无法通过引用变量 r 修改 j 的值,可能与 Release 模式下编译器对引用的优化有关。与此同时,该程序可移植性很差,在 64bits 平台上,由指针转换为 int 可能会发生截断从而丢失数据。其次,如果引用变量前的变量不是 int 型,考虑到内存对齐等因素,要准确计算引用变量的地址不是一件容易的事,很可能跟具体的编译器和运行环境相关。因此,研究此程序的目的是为了对引用变量的底层实现机制有所了解。在实际使用中,还是要遵循 C++ 语言对引用制定的规范。


    参考文献

    陈刚.C++高级进阶教程[M].武汉:武汉大学出版社,2008.
    vs栈上连续定义的int变量,地址为什么相差12个字节

    更多相关内容
  • 很多视频讲解都只停留在语法层面,没有触及右值引用本质,让人很迷惑。 希望这个解析可以让你对它的本质有所了解。 右值引用还是引用。 针对右值,在汇编阶段时,会在栈中存储右值,变成一个有地址的变量。 然后将...

    C++11右值引用的特性很重要,在很多场合可以提升性能,实际上C++中所谓提升性能的操作往往是以引用的形式实现的,右值引用就是这样。从语言的层面来说因为引用了右值引用这一个新的特性,便与众多的语法特性产生了关联,进一步增加了学习C++的难度。很多视频讲解都只停留在语法层面,没有触及右值引用的本质,让人很迷惑。

    希望这个解析可以让你对它的本质有所了解。

    4d2705e9e8c2ba50dd088769ac5afcea.png

     右值引用还是引用。

    针对右值,在汇编阶段时,会在栈中存储右值,变成一个有地址的变量。

    然后将该变量的地址进行左值引用(即别名)来使用。

    展开全文
  • C++引用本质

    2022-02-05 20:24:51
    引用的本质是指针常量:数据类型 * const 变量名。 指针常量的指向不可以变,指向的值可以...而引用本质就是指针常量。引用不可以指向其他变量,但是可以赋以新的值。内部慧自动识别引用进行解引用。如下图。 ...

    引用的本质是指针常量:数据类型 * const 变量名。

    指针常量的指向不可以变,指向的值可以变。

    如:int * const b=&a;

    b=&c;是错误的,不能让b指向新的地址。

    *b=10;是对的,可以改变b指向的值,即将b指向的地址存储的值 赋为 新的值。

    而引用本质就是指针常量。引用不可以指向其他变量,但是可以赋以新的值。编译器内部会自动识别引用进行解引用。如下图。

    展开全文
  • C++ 引用本质

    2021-12-14 13:16:12
    引用本质 本质引用本质在C++内部实现是一个指针常量 #include <iostream> using namespace std; int main() { int num = 100; //自动转换为 int* const ref = &a; 指针常量是指针指向不可更改,...

    引用的本质

    本质:引用的本质在C++内部实现是一个指针常量

    #include <iostream>
    using namespace std;
    int main()
    {
    	int num = 100;
    
    	//自动转换为 int* const ref = &num; 指针常量是指针指向不可更改,也说明为什么引用不可更改
    	int& ref = num;
    	ref = 20;  //内部发现ref是引用,自动帮我们转换为:*ref = 20;
    	
    	cout << "num:" << num << endl;
    	cout << "ref:" << ref << endl;
    	
    	return 0;
    }
    

    在这里插入图片描述

    在这里插入图片描述

    展开全文
  • C++引用本质

    2020-10-09 21:13:47
    那么引用本质是什么,它与指针又有什么关系呢? 1.引用的底层实现方式 引用被称为变量的别名,它不能脱离被引用对象独立存在,这是在高级语言层面的概念和理解,并未揭示引用的实现方式。常见错误说法是“引用...
  • 引用本质

    2022-07-12 10:04:50
    引用本质
  • 引用实质是指针常量,相当于int * const b = & a; void test01() { int a = 10; int& b = a;//引用实质是指针常量,相当于int * const b = & a; b = 12;//内部发现是引用,变为*b=12; cout <<...
  • 在某实践中想通过通信直接读取内存的值查看某个变量(一个引用变量),地址的值是通过map文件解析出来的, 读出来以后发现数据值...这说明本质引用是作为指针来处理的,引入引用可能只是为了语义更清晰,书写更方便
  • 引用本质思考: 思考、C++编译器背后做了什么工作? #include using namespace std; int main() { int a = 10; // 单独定义的引用时,必须初始化;说明很像一个常量 int &b = a; // b是a的别名 b = 11; ...
  • C++中引用本质

    2021-01-16 08:29:37
    一、引用本质 我不会告诉你,引用是“别名”,这更加令人难以琢磨… 引用本质就是带有const的指针 引用本质就是带有const的指针 引用本质就是带有const的指针 int & a = b <---> int *const a = &...
  • 引用本质是什么?

    2020-03-24 11:49:09
    *和const谁在前,就先念谁 故const int *p叫做常量指针(也可以写作int const *p) ...但是可以执行*p=x的操作 引用本质就是指针常量,指向的地址不能修改 https://www.cnblogs.com/rollenholt/articles/1907408.html
  • 0、传统的左值引用是这样的: int a = 123; int &b = a; // 定义一个左值引用变量 b = 456; // 通过左值引用修改引用内存的值 1、如何理解左值引用呢? 在汇编视角,都是指针 在编译器视角,左值引用只是一...
  • 参考文章: 1.C++的那些事:你真的了解引用吗 2.引用本质是什么?
  • 引用本质分析

    千次阅读 2019-09-22 13:12:51
    第一点:首先我们知道,引用(&)是C++用一个特有的概念,它的意思就是对一个变量取别名,操作变量的别名就相当于操作...其实C++中引用本质就是指针,引用在C++的内部实现就是一个常量指针。int& p<-->...
  • 引用本质,常量引用的作用,建议使用const的理由
  • 1.实质:一切引用传递的本质上就是传值;2.基本类型与引用类型:int num=10; num是基本类型,值就是直接保存在变量中。String str="hello"; str是引用类型,变量中保存的只是实际对象的地址,一般称这种变量为“引用...
  • 在 Java 语言中,除了原始数据类型的变量,其他所有都是所谓的引用类型,指向各种不同的对象,理解引用对于掌握 Java 对象生命周期和 JVM 内部相关机制非常有帮助。 在Java语言中,除了基本数据类型外,其他的都是...
  • 引用本质 引用本质是常指针 C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占的空间大小与指针相同。 由编译器内部实现,用户不可见 ref = 100l; //ref是引用 ---> *ref=100; int a=10; ...
  • 引用本质在C++内部是一个指针常量。 如:int a = 10; int& b = a; 就相当于intconst b = &a; 我们知道指针常量是不能再指向其他变量的,也就是它的地址不能变了,所以b只能作为a的别名,而不能再作为其他...
  • ①C++中的引用本质上是 一种被限制的指针(类似于线性表和栈,栈是被限制的线性表,底层实现相同,只不过逻辑上的用法不同而已)。 ②由于引用是被限制的指针,所以引用是占据内存的。 ③在使用高级语言的层面上,...
  • C++11右值引用本质是什么?

    千次阅读 2015-11-13 11:34:25
    C++11右值引用本质是什么?我认为从编译器层面讲本质就是一种表达方式,主要是为了告诉编译器如何生成代码,从逻辑层面讲,主要是为了解决对象构造内存拷贝开销大的问题。请赐教。
  • C++中引用本质分析

    2019-07-12 16:59:18
    引用是C++中心增加的内容,在C语言是没有引用这一种用法的。那什么是引用呢? 大家都知道,我们定义变量的时候,其实是将变量名和内存空间关联起来,变量名就是一段内存空间的别名。当我们使用引用的时候,例如int&...
  • 下面小编就为大家带来一篇JavaScript数据操作_浅谈原始值和引用值的操作本质。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 10.4 引用本质

    2020-06-30 23:19:41
    10.4 引用本质 引用本质其实是一个指针常量。 也就是说: int &b = a; 本质上是: int* const b = &a; 回想一下引用的一个特性(引用一旦确定了引用关系就不能改变)不难发现,这与指针常量的特性...
  • 引用和指针的区别

    千次阅读 多人点赞 2020-08-08 17:02:45
    引用和指针的区别:

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 437,312
精华内容 174,924
关键字:

引用的本质

友情链接: VUMAT_UMATinterface.tar.gz