为何为局部变量创建指针需在栈上分配空间?
为什么C语言中对局部变量取
&时不能将变量存在寄存器中? 核心原因:指针的本质是内存地址
C语言里&操作符的核心作用是返回变量的内存地址,而CPU的通用寄存器和内存是完全独立的硬件单元:
- 寄存器的访问依赖硬件层面的寄存器编号(比如x86-64的
%rax、%rbx),并不属于进程的虚拟内存地址空间,没有可被外部引用的内存地址。 - 指针的语义要求它指向一个可寻址、可读写的内存位置,寄存器根本满足不了这个前提。
强行这么做的后果
如果编译器硬给寄存器里的变量生成一个“伪地址”,会引发一系列致命问题:
- 直接触发段错误:这个伪地址不属于进程的合法地址空间,内存管理单元(MMU)无法找到对应的物理内存映射,程序会直接崩溃。
- 数据被意外覆盖:寄存器是整个程序共享复用的资源,比如
swap_add函数可能会用同一个寄存器存临时值,直接覆盖原变量内容,彻底打乱程序逻辑。 - 违反指针语义:指针支持解引用、加减偏移(比如
ptr+1)等操作,这些操作依赖内存地址的连续空间特性,寄存器没有这类属性,根本无法支持。
x86-64架构的具体规则
x86-64遵循的System V AMD64应用二进制接口(ABI)明确规定:当局部变量被取地址时,必须将其分配到栈上(或堆内存,但局部变量默认用栈)。编译器会自动把这类变量从寄存器“溢出”到栈帧中,生成合法的内存地址供&操作符返回。
以你给出的代码为例:
long caller() { long arg1 = 534; long arg2 = 1057; long sum = swap_add(&arg1, &arg2); // arg1和arg2必须在栈上 long diff = arg1 - arg2; return sum * diff; }
编译器会在caller的栈帧里为arg1和arg2分配空间,swap_add才能通过指针正常访问和修改它们的值。
其他架构的情况
绝大多数通用CPU架构的规则和x86-64一致:
- ARM/RISC-V:通用寄存器同样没有内存地址,被取地址的局部变量必须分配到栈或全局内存中。
- 内存映射寄存器(特殊案例):部分嵌入式或外设架构里,存在被映射到内存地址空间的寄存器(比如外设控制寄存器),这类寄存器可以被取地址,但它们是硬件设计的特殊情况,并非普通通用寄存器,也不会用来存储普通局部变量。
内容的提问来源于stack exchange,提问作者John Smith
相关产品推荐
相关产品推荐

