我将尝试解释 g++ 编译器是如何实现引用的。
#include <iostream>
using namespace std;
int main()
{
int i = 10;
int *ptrToI = &i;
int &refToI = i;
cout << "i = " << i << "\n";
cout << "&i = " << &i << "\n";
cout << "ptrToI = " << ptrToI << "\n";
cout << "*ptrToI = " << *ptrToI << "\n";
cout << "&ptrToI = " << &ptrToI << "\n";
cout << "refToNum = " << refToI << "\n";
//cout << "*refToNum = " << *refToI << "\n";
cout << "&refToNum = " << &refToI << "\n";
return 0;
}
这段代码的输出是这样的
i = 10
&i = 0xbf9e52f8
ptrToI = 0xbf9e52f8
*ptrToI = 10
&ptrToI = 0xbf9e52f4
refToNum = 10
&refToNum = 0xbf9e52f8
让我们看一下反汇编(我为此使用了 GDB。这里的 8,9 和 10 是代码的行号)
8 int i = 10;
0x08048698 <main()+18>: movl $0xa,-0x10(%ebp)
这里$0xa 是我们分配给i 的10(十进制)。 -0x10(%ebp) 这里表示ebp register –16(十进制)的内容。
-0x10(%ebp) 指向栈上i 的地址。
9 int *ptrToI = &i;
0x0804869f <main()+25>: lea -0x10(%ebp),%eax
0x080486a2 <main()+28>: mov %eax,-0x14(%ebp)
将i的地址分配给ptrToI。 ptrToI 再次位于地址-0x14(%ebp) 的堆栈上,即ebp – 20(十进制)。
10 int &refToI = i;
0x080486a5 <main()+31>: lea -0x10(%ebp),%eax
0x080486a8 <main()+34>: mov %eax,-0xc(%ebp)
现在问题来了!对比第 9 行和第 10 行的反汇编,你会发现,-0x14(%ebp) 在第 10 行被替换为-0xc(%ebp)。-0xc(%ebp) 是refToNum 的地址。它在堆栈上分配。但是你永远无法从你的代码中得到这个地址,因为你不需要知道这个地址。
所以;引用确实占用内存。在这种情况下,它是堆栈内存,因为我们已将其分配为局部变量。
它占用多少内存?
一个指针占用多少空间。
现在让我们看看我们如何访问引用和指针。为简单起见,我只展示了组件 sn-p 的一部分
16 cout << "*ptrToI = " << *ptrToI << "\n";
0x08048746 <main()+192>: mov -0x14(%ebp),%eax
0x08048749 <main()+195>: mov (%eax),%ebx
19 cout << "refToNum = " << refToI << "\n";
0x080487b0 <main()+298>: mov -0xc(%ebp),%eax
0x080487b3 <main()+301>: mov (%eax),%ebx
现在比较上面两行,你会发现惊人的相似。 -0xc(%ebp) 是 refToI 的实际地址,您永远无法访问。
简单来说,如果您将引用视为普通指针,那么访问引用就像在引用指向的地址处获取值。这意味着下面两行代码会给你同样的结果
cout << "Value if i = " << *ptrToI << "\n";
cout << " Value if i = " << refToI << "\n";
现在比较一下
15 cout << "ptrToI = " << ptrToI << "\n";
0x08048713 <main()+141>: mov -0x14(%ebp),%ebx
21 cout << "&refToNum = " << &refToI << "\n";
0x080487fb <main()+373>: mov -0xc(%ebp),%eax
我想你能够发现这里发生了什么。
如果查询&refToI,则返回-0xc(%ebp)地址位置的内容,-0xc(%ebp)是refToi所在的位置,其内容就是i的地址。
最后一件事,为什么要评论这一行?
//cout << "*refToNum = " << *refToI << "\n";
因为*refToI 是不允许的,它会给你一个编译时错误。