众所周知,引用是某一个变量的别称。指针是一个变量,变量的内容是某一个变量的地址
下面从实现方式和应用两个维度剖析这两者的不同
指针的实现指针从本质上来讲还是一个变量。和普通变量不一样的是:指针变量中存放的是其他变量的地址(变量都是需要占用存储空间的,有一个对应的地址)。
引用的实现之前自己理解的引用不是变量。是在编译期间被编译器替换掉的一个符号,相当于是一个宏。这个理解是错误的。引用是一个变量,实现上可以把他当成一个不能改变其内容的指针。看下面代码的反汇编
源码:
#include#include void func(int& a) { a = 1; printf("func a address:%pn", &a); return; } int main(int argc, char* argv[]) { int mainA = 2; printf("main mainA address:%pn", &mainA); func(mainA); int & A = mainA; A = 3; printf("main A address:%pn",&A); return 0; }
函数func对应的汇编代码
0804841d <_Z4funcRi>: 804841d: 55 push %ebp 804841e: 89 e5 mov %esp,%ebp 8048420: 83 ec 18 sub $0x18,%esp 8048423: 8b 45 08 mov 0x8(%ebp),%eax 8048426: c7 00 01 00 00 00 movl $0x1,(%eax) 804842c: 8b 45 08 mov 0x8(%ebp),%eax 804842f: 89 44 24 04 mov %eax,0x4(%esp) 8048433: c7 04 24 30 85 04 08 movl $0x8048530,(%esp) 804843a: e8 b1 fe ff ff call 80482f0804843f: 90 nop 8048440: c9 leave 8048441: c3 ret
指令8048423处是把入栈的参数放到寄存器eax中。指令8048426处是把数字1放入eax所指示的地址上。那么我们需要搞清楚在调用函数func的时候入栈的参数是什么?
看下main函数的汇编代码
08048442: 8048442: 55 push %ebp 8048443: 89 e5 mov %esp,%ebp 8048445: 83 e4 f0 and $0xfffffff0,%esp 8048448: 83 ec 20 sub $0x20,%esp 804844b: c7 44 24 18 02 00 00 movl $0x2,0x18(%esp) 8048452: 00 8048453: 8d 44 24 18 lea 0x18(%esp),%eax 8048457: 89 44 24 04 mov %eax,0x4(%esp) 804845b: c7 04 24 43 85 04 08 movl $0x8048543,(%esp) 8048462: e8 89 fe ff ff call 80482f0 8048467: 8d 44 24 18 lea 0x18(%esp),%eax 804846b: 89 04 24 mov %eax,(%esp) 804846e: e8 aa ff ff ff call 804841d <_Z4funcRi> 8048473: 8d 44 24 18 lea 0x18(%esp),%eax 8048477: 89 44 24 1c mov %eax,0x1c(%esp) 804847b: 8b 44 24 1c mov 0x1c(%esp),%eax 804847f: c7 00 03 00 00 00 movl $0x3,(%eax) 8048485: 8b 44 24 1c mov 0x1c(%esp),%eax 8048489: 89 44 24 04 mov %eax,0x4(%esp) 804848d: c7 04 24 5a 85 04 08 movl $0x804855a,(%esp) 8048494: e8 57 fe ff ff call 80482f0 8048499: b8 00 00 00 00 mov $0x0,%eax 804849e: c9 leave 804849f: c3 ret
指令804844b处,把数字2赋值给变量mainA。指令8048467及后面的两条指令是对函数func的调用。分析这三条指令
指令8048467: 把esp+0x18 (变量mainA的地址)赋值给寄存器eax。
指令804846b: 把eax的值入栈。
指令804846e: 调用函数func。
可以得出结论:调用函数func时,入栈的参数是变量mainA的地址。函数调用过程的引用变量传递的是变量的地址。那么还有另外一个问题:在非函数调用的场景下,引用变量是怎么实现的呢
分析main函数中的引用变量A是怎么实现的,有关的指令为8048473及其后的三条指令
指令8048473:把esp+0x18(变量mainA的地址)赋值给寄存器eax
指令8048477:把eax的值放到esp+0x1c(变量A的地址)指示的地址空间中
指令804847b:把esp+0x1c(变量A的地址)地址空间中的内容(变量mainA的地址)赋值给寄存器eax,
指令804847f:把数字3放到eax指示的地址空间中
可以得出结论:在非函数调用的场景下,引用变量也是通过指针实现的。
编译器在处理引用变量的特殊处理:(待验证)
1. 对于引用变量 取地址符& 获取的是引用变量的内容,而并非是引用变量的地址
2. 对于引用变量的赋值,把需要赋值的内容放到引用变量的内容所指示的地址空间中
那么对于多级引用的情况是什么样子的呢?todo
1. int a =2; int & b = a; int & c = b;
引用的使用可以把引用的使用当成一个不能改变其内容的指针变量。而普通的指针变量是可以改变变量中的内容的



