结论
引用的本质是指针
代码
本次代码编译器为 x86_64 gcc 10.1,同时禁用优化
AT&T风格汇编
在线编译环境
int main()
{
int number = 10;
int &ref = number;
int *ptr = &number;
return 0;
}
以下是对应的汇编代码
// gcc 局部变量存放规则
// 第一个出现的变量用于给所有局部变量在栈上申请内存,所以此处number的内存为rbp - 20
// 后面按局部变量出现的位置顺序排
main:
pushq %rbp
movq %rsp, %rbp
movl $10, -20(%rbp) // rbp - 20 是nuber的内存起始地址, 此处是给number赋值
leaq -20(%rbp), %rax // 将rbp中的值减去20赋值给rax,所以rax存放的是number的起始地址
movq %rax, -8(%rbp) // 将rax中8字节值赋值给rbp-8,rbp-8的位置为ref的内存地址,所以这两句是给ref赋值
leaq -20(%rbp), %rax
movq %rax, -16(%rbp) // 同理,这两句就是给ptr赋值,通过对比这两处赋值可以发现,引用和指针在汇编层面上是一致的
movl $0, %eax
popq %rbp
ret
问题
1、为什么是减去20字节
因为main函数中共使用3个变量(返回值存储到eax中不参与计算),分别是number,ref,ptr
已知number和ptr分别占用4字节,8字节,剩余的8字节就是ref的占用,所以是减去20字节
2、lea命令
lea命令用于计算地址,比如leaq -20(%rbp), %rax
表示将rbp寄存器的值减去20所得的值赋值给rax
rbp寄存器存放的是main函数的栈基指针,即栈的起始地址
其他编译器编译此处代码
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
gcc test.cc -o test.s -S -O0
main:
pushq %rbp
movq %rsp, %rbp
subq $32, %rsp // 此处是用于开辟栈上内存,x86的栈向下增长,所以是sub
movq %fs:40, %rax
movq %rax, -8(%rbp)
xorl %eax, %eax
movl $10, -28(%rbp) // number内存赋值
leaq -28(%rbp), %rax // 将number内存地址赋值给rax
movq %rax, -24(%rbp) // 将rax寄存器的值赋值给ref
leaq -28(%rbp), %rax
movq %rax, -16(%rbp) // 将rax寄存器的值赋值给ptr
movl $0, %eax
movq -8(%rbp), %rdx
xorq %fs:40, %rdx
leave
ret