内容简介:本问题的关键是一个视角问题。同一个问题,站在C++程序员的角度与站在编译器开发者的角度来看是不一样的。在C++中我们说“引用不占内存”是从C++程序员的角度来看。请看下列程序的运行结果。
本问题的关键是一个视角问题。同一个问题,站在C++程序员的角度与站在编译器开发者的角度来看是不一样的。
在C++中我们说“引用不占内存”是从C++程序员的角度来看。请看下列程序的运行结果。
#include <iostream> using namespace std; int main(int argc, char** argv) { char c; double i; double &k = i; char &m = c; double *p = &i; char *q = &c; cout << "Result :" << endl; cout << " i = " << sizeof(i) << endl; cout << " k = " << sizeof(k) << endl; cout << " c = " << sizeof(c) << endl; cout << " m = " << sizeof(m) << endl; cout << " p = " << sizeof(p) << endl; cout << " q = " << sizeof(q) << endl; return 0; }
运行结果为:
Result : i = 8 k = 8 c = 1 m = 1 p = 4 q = 4
显然,对于引用变量k来说,sizeof(k)的结果为8,sizeof(m)的结果为1,这样的结果实际是被引用对象所占内存的大小,k引用的是double类型,所以占8个字节;m引用的是char类型,所以占1个字节。这与指针变量完全不同,从运行结果可以看出,不论指针变量指向的数据类型是什么,指针变量(p、q)均占用4个字节。进一步可以用C++程序证明,对于引用变量的处理直接操作的对象就是被引用对象。所以从C++的角度来说,引用本身不会为变量开辟新的存储空间,引用只是为实际对象起了一个别名。
C++程序不能在计算机上直接运行,必须经过编译器将C++程序编译生成汇编程序,从编译的角度来看,C++编译器对引用的处理与对于指针的处理是相同的,均是为变量分配一个对应的内存空间。所以,站在编译器开发者的角度来看,在编译器中要实现引用就必须要为引用变量分配一个内存空间。
所以两个视角不能混淆。
为了更深入解释,我们可以在DEV C++环境中运行下列C++程序。
#include <iostream> using namespace std; int main(int argc, char** argv) { int i = 5; int j = 6; int &k = i; int *p = &i; i = j; k = j; i = k; &k = j; // 编译错误,无法通过 cout << "运行结果:" << endl; cout << " i = " << i << endl; cout << " &i = " << &i << endl; cout << " j = " << j << endl; cout << " k = " << k << endl; cout << " &k = " << &k << endl; cout << " p = " << p << endl; cout << " &p = " << &p << endl; return 0; }
运行结果:
i = 6 &i = 0x22fe98 j = 6 &j = 0x22fe94 k = 6 &k = 0x22fe98 p = 0x22fe98 &p = 0x22fe90
上述C++程序对应的汇编代码如下:
0x00401576 <+86>: mov DWORD PTR [ebp-0x20],0x5
; 语句i = 5。ebp=0x22feb8
0x0040157d <+93>: mov DWORD PTR [ebp-0x24],0x6
; 语句j = 6
0x00401584 <+100>:lea eax,[ebp-0x20]
; 语句&k = i。eax=0x22fe98
0x00401587 <+103>:mov DWORD PTR [ebp-0x1c],eax 0x0040158a <+106>: lea eax,[ebp-0x20]
; 语句p = &i。eax=0x22fe98
0x0040158d <+109>:mov DWORD PTR [ebp-0x28],eax 0x00401590 <+112>:mov eax,DWORD PTR [ebp-0x24]
; 语句i = j。eax=0x6
0x00401593 <+115>:mov DWORD PTR [ebp-0x20],eax 0x00401596 <+118>:mov edx,DWORD PTR [ebp-0x24]
; 语句k = j。
0x00401599 <+121>:mov eax,DWORD PTR [ebp-0x1c] 0x0040159c <+124>: mov DWORD PTR [eax],edx 0x0040159e <+126>: mov eax,DWORD PTR [ebp-0x1c]
; 语句i = k。
0x004015a1 <+129>: mov eax,DWORD PTR [eax] 0x004015a3 <+131>: mov DWORD PTR [ebp-0x20],eax 0x004015a6 <+134>: mov eax,DWORD PTR [ebp-0x28]
; 语句*p = j。
0x004015a9 <+137>: mov edx,DWORD PTR [ebp-0x24] 0x004015ac <+140>: mov DWORD PTR [eax],edx 0x004015ae <+142>: mov eax,DWORD PTR [ebp-0x20]
; 下一条语句
0x004015b1 <+145>: ……
通过分析可以看到,整型变量i在内存中分配的绝对地址为0x22fe98,相对地址为ebp-0x20;整型变量j的绝对地址为0x22fe94,相对地址为ebp-0x24;指针变量p的绝对地址为0x22fe90,相对地址为ebp-0x28;引用变量k在内存中相对地址为ebp-0x1c。注意:在C++程序员的视角中是无法得到引用变量k在内存中的地址。变量在内存中地址分配关系见下表。
将C++程序与对应的汇编指令相对照。语句“&k = i”对应的汇编语句是<+100>和<+103>,编译为引用变量k分配了内存单元,且保存的是变量i的地址,语句“p = &i”的汇编语句是<+106>和<+109>,编译为指针变量p分配了内存单元,且保存的是变量i的地址,两个语句对应的汇编是一样的,都是在变量对应的单元中保存了相关对象的地址。
语句“k = j”对应的汇编语句是<+118>、<+121>和<+124>,语句“*p = j” 对应的汇编语句是<+134>、<+137>和<+140>,两相对照,生成的汇编指令没有本质区别,可以认为是完全等价的。因此可以得出结论,通过编译之后,生成的最终代码在汇编级对于引用变量和指针变量的处理是相同的。
在C++的视角来看,引用变量与指针变量是不同的。指针变量是一个实体,在运行过程中可以改变;而引用仅是某个变量的别名,引用变量在被创建的同时必须被初始化,且在运行过程中不能被再次改变。
在我们给出的上述源程序示例中,语句“&k = j;”是无法通过编译。因此可以认为,C++语言中对于引用型变量的限制是由编译器本身限制的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- OC内存管理--引用计数器
- 内存二三事: Xcode 内存图、Instruments 可视化检测循环引用
- 如何使用弱引用优化 Python 程序的内存占用?
- 深入理解JVM虚拟机-对象引用,GC与内存分配回收
- 写给前端的手动内存管理基础入门(一):返璞归真之从引用类型到裸指针
- 强引用、软引用、弱引用、虚引用
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
ANSI Common Lisp
Paul Graham / Prentice Hall / 1995-11-12 / USD 116.40
For use as a core text supplement in any course covering common LISP such as Artificial Intelligence or Concepts of Programming Languages. Teaching students new and more powerful ways of thinking abo......一起来看看 《ANSI Common Lisp》 这本书的介绍吧!
URL 编码/解码
URL 编码/解码
UNIX 时间戳转换
UNIX 时间戳转换