C++笔记 引用
引用的作用:
类似与指针的效果,发挥的作用与指针相似。可以认为是一直隐式指针。
如下代码:
#include <iostream>
using namespace std;
int main()
{
int i = 10;
int& n = i;
cout << i << endl;
cout << n << endl;
}
查询变量地址可以得到:
可以看到的是两个地址是一模一样的,存放的内容为0x0a如图:
问题1?引用自身是否会和指针一样申请地址?来存放引用的地址?
汇编解析:
int main()
{
00007FF625845040 push rbp
00007FF625845042 sub rsp,80h
00007FF625845049 lea rbp,[rsp+20h]
00007FF62584504E mov rax,qword ptr [__security_cookie (07FF62584C010h)]
00007FF625845055 xor rax,rbp
00007FF625845058 mov qword ptr [rbp+50h],rax
00007FF62584505C lea rcx,[__1919B843_main@cpp (07FF62585218Eh)]
00007FF625845063 call __CheckForDebuggerJustMyCode (07FF6258413C0h)
int i = 10;
00007FF625845068 mov dword ptr [rbp],0Ah
int& n = i;
00007FF62584506F lea rax,[rbp]
00007FF625845073 mov qword ptr [n],rax
.....
通过底层汇编代码可以看到n是存在一个地址的也就是和指针类似。
如图:
注意注意!!!!由于vs自带的反汇编导致有误导,使用xdbug64来进行分析得到的结果截然不同。
mov dword ptr ss:[rbp], A | 0000001F97CFF5A0 变量x
lea rax, qword ptr ss:[rbp] | main.cpp:6
mov qword ptr ss:[rbp+8], rax| 引用 地址为 0000006A6EDCF970
从逆向层面进行分析发现这个引用变量并没有一个地址进行永久存放取而代之的是将a的地址存入堆栈中也就是rbp+0x8这个位置请看堆栈。并不存在n这个地址。
从代码层面进行分析:
打印它们之间的地址会发现地址是一样的。如果没有对这个引用进行初始化绑定编译器会自动提示报错。
问题2?引用与指针之间的区别在哪?
代码层面:
- 引用必须先进行初始化绑定否则会报错。
- 不能像指针一样进行二级指针。
- 指针的大小和引用所占的空间是不一样的。因为64的缘故指针存储地址肯定是一个8字节,而引用则直接取的是变量x的大小。这有本质区别。
- 引用一旦初始化绑定后就无法修改。如果强行修改,则会导致原本绑定指向的变量直接发生改变。在代码层面就可以认为它和绑定的变量本身没有任何区别。
- 指针可以进行自增,自减达到移位作用但是引用无法进行移位。
总结:
我们可以把引用认为是一个"伪指针"。减少了一些指针操作不当或者程序员水平有限造成的各种问题,引用可以更好的避免这个问题,同时从代码层面上来使用方式更加接近Python或者Java这种没有指针的语言。有点类似与Python的赋值。需要注意的是一旦绑定后就无法在对引用变量进行解绑操作。这个伪指针从底层来看就是一个存放在堆栈的临时地址,所以我们对他的操作都是其实对变量进行操作。而指针在定义的时候就有一个固定的地址存放,所以底层实现方式是截然不同的!!!它们只是用法上相似但是从底层来看不是一个东西!