C 语言 swap 函数底层原理
在 C 语言开发中,swap 函数看似简单,但其背后的内存操作机制往往被初学者忽略。理解它是如何工作的,关键在于看清编译器生成的汇编代码以及栈帧(Stack Frame)的变化。
汇编基础指令回顾
在深入代码之前,先快速过一遍 ARM 汇编中常用的数据搬运指令,这对理解后续逻辑至关重要。
存储指令 (STR)
格式:STR{条件} 源寄存器,<存储器地址>
STR R0, [R1], #8:将 R0 写入 R1 指向的地址,然后 R1 自动加 8。STR R0, [R1, #8]:将 R0 写入 R1+8 指向的地址,R1 不变。
加载指令 (LDR)
格式:LDR{条件} 目的寄存器,<存储器地址>
LDR R0, [R1]:从 R1 指向的地址读取数据到 R0。LDR R0, [R1, #8]!:从 R1+8 读取数据到 R0,并将 R1 更新为 R1+8(写回模式)。
值传递的汇编实现
当我们定义一个普通的 swap(int a, int b) 时,参数是按值传递的。这意味着函数内部操作的是副本,不会影响外部变量。
void swap(int a, int b) {
int temp;
temp = a;
a = b;
b = temp;
}
void main(void) {
int x = 2, y = 3;
swap(x, y);
}
编译后的汇编逻辑分析:
进入 swap 函数后,CPU 会执行标准的栈帧创建流程。首先调整栈指针 SP 和帧指针 FP,为局部变量 temp 分配空间。
AREA SwapVal, CODE, READONLY
ENTRY
MOV sp, #0x1000 ; 初始化栈指针
MOV fp, #0xFFFFFFFF ; 初始化帧指针
B main ; 跳转至主函数
; void swap(int a, int b)
swap SUB sp, sp, #4 ; 创建栈帧,SP 下降
STR fp, [sp] ; 保存旧帧指针
MOV fp, sp ; 设置新帧指针
SUB sp, sp, #4 ; 为局部变量 temp 分配空间
LDR r0, [fp, #4] ; 获取参数 a 的值
STR r0, [fp, #-4] ; 存入 temp
LDR r0, [fp, #8] ; 获取参数 b 的值
STR r0, [fp, #4] ; 存入 a
LDR r0, [fp, #-4] ; 获取 temp 的值
STR r0, [fp, #8] ; 存入 b
MOV sp, fp ; 恢复栈指针
LDR fp, [fp] ; 恢复旧帧指针
ADD sp, sp, #4 ; 清理局部变量空间
MOV pc, lr ; 返回调用者
注意看 main 函数中的调用过程。虽然我们在 C 代码里写了 swap(x, y),但在汇编层面,x 和 y 的值被压入栈中作为实参传递给 。函数内部对 和 的修改,仅仅是在 自己的栈帧内进行的。一旦函数返回,这些栈空间被释放, 函数里的 和 毫发无损。


