这里理论上来说应该是指向test函数中行参n的地址。如果编译的时候不启用优化,那么输出的结果应该就是10。
我们认为函数返回后就不应该访问它的局部变量,因为当我们后续调用函数的时候可能会覆盖掉它的值,但是它的局部变量的地址仍然是存在的。要详细了解这一部分内容需要一点内存管理的知识,了解内存中的栈和堆,还有函数调用是在栈上就够了。
而这份代码恰好很幸运,在调用printf函数前,编译器预先将*p的值读入了寄存器中,然后才调用printf函数。
我在ubuntu20.04上用gdb调试了一下,p=test(a)和printf("%d\n",*p)这部分代码汇编代码的执行过程大概是这样的:
在test函数中,n被存储到了地址p = 0x7fffffffde8c,然后test函数返回给p的值是p = 0x7fffffffde8c,p=test(a)执行完毕。这部分内存属于栈内存。
printf("%d\n",*p)的汇编代码如下:0x000055555555516e <+37>: mov (%rax),%eax # 此时%rax存储的是p,这里将*p传入%eax寄存器
0x0000555555555170 <+39>: mov %eax,%esi # 通常%esi寄存器保存函数的第二个参数
0x0000555555555172 <+41>: lea 0xe8b(%rip),%rdi # 把字符串"%d\n"的地址传入%rdi
0x0000555555555179 <+48>: mov $0x0,%eax # %eax通常存储函数返回值,清零%eax
0x000055555555517e <+53>: callq 0x555555555050 <printf@plt> # 调用printf
所以实际上,在0x000055555555516e <+37>: mov (%rax),%eax这一行,*p就已经被保存在寄存器中了。而此时还没有执行callq 0x555555555050 <printf@plt>,因此test原来占用的栈帧没有被改变,故p指向的内容还是10。 |