首先百度一下
1. 什么是函数栈帧?
函数栈帧(Function Stack Frame)是程序在调用函数时在栈上分配的一段内存,用于保存函数的局部变量、返回地址、传递的参数以及其他必要的信息。栈帧的存在使得函数可以在调用之间保存上下文,确保函数返回时可以恢复现场。
想象一下栈帧就像一叠盘子,每调用一个函数就放上一个新盘子,函数结束时就取走最上面的盘子。因此,这个"栈"是后进先出的结构。
2. 函数栈帧的创建过程
当函数被调用时,会经历以下几个步骤来创建一个新的栈帧:
-
保存返回地址:当前函数执行到一个新的函数调用时,必须知道未来如何返回,因此先把当前指令的返回地址保存到栈中。
-
分配局部变量空间:为函数的局部变量分配内存。所有的局部变量都在栈帧中保存,直到函数调用结束。
-
保存寄存器内容(可选):在有些情况下,程序会保存一些重要寄存器的内容,以防止新函数修改它们。
-
传递参数:把需要传递给被调用函数的参数放入栈中。参数通常从右到左入栈,以保证函数的第一个参数在栈顶。
下图展示了函数调用时的栈帧结构:
3. 函数栈帧的销毁过程
当函数执行结束并返回时,栈帧会被销毁。销毁的过程通常如下:
-
恢复寄存器内容:从栈中恢复被保存的寄存器,以确保返回后系统状态与调用前保持一致。
-
释放局部变量空间:局部变量的内存会被标记为未使用。实际上,并不会真正删除这些内存,而是允许其他函数复用它们。
-
跳转到返回地址:使用保存在栈中的返回地址,跳转到调用函数的下一条指令位置,继续执行程序。
通过这种机制,函数可以一次又一次被安全调用,而不影响彼此的运行。
4. 代码示例和分析
以下是一个简单的C++代码示例,用来说明函数栈帧的创建与销毁过程:
#include <iostream> void foo(int a) { int b = a + 5; // 局部变量 b std::cout << "b = " << b << std::endl; } int main() { int x = 10; foo(x); // 调用函数 foo return 0; }
代码分析
调用
foo(x)
时:
栈帧被创建,
x
的值(10)被传递给foo
的参数a
。为局部变量
b
分配内存,并计算b = a + 5
,也就是b = 15
。调用
std::cout
打印b
的值。函数
foo
执行结束后:
栈帧被销毁,局部变量
a
和b
的内存被释放。程序跳回到
main
函数继续执行。
5. 图解函数栈帧的变化
底下用图解展示函数栈帧的变化过程,方便理解。
1
main
函数调用foo
之前
2 调用
foo(x)
时
3
foo
函数结束后
在调用 foo
的时候,一个新的栈帧被压入栈中,当 foo
返回时,栈帧被弹出,这样就确保每次函数的局部变量和状态相互隔离,不会相互影响。
复盘
-
栈帧是用来管理函数调用的机制,每个函数调用都会创建一个栈帧来保存其状态(局部变量、参数、返回地址等)。
-
栈是后进先出(LIFO)结构,每次调用函数时都会增加栈帧,返回时会销毁栈帧。
-
通过栈帧,程序可以实现递归和嵌套调用,并确保函数之间不会相互干扰。
共勉 💪
同为未来的it人让我们在共同进步吧。
我很喜欢雷军的一段话:我们就悄悄的干,就算失败了咱也不丢人。