《图解C++函数栈:从创建到销毁,一看就懂的完整指南》

首先百度一下

1. 什么是函数栈帧?

栈(计算机术语)_百度百科

函数栈帧(Function Stack Frame)是程序在调用函数时在栈上分配的一段内存,用于保存函数的局部变量、返回地址、传递的参数以及其他必要的信息。栈帧的存在使得函数可以在调用之间保存上下文,确保函数返回时可以恢复现场。

想象一下栈帧就像一叠盘子,每调用一个函数就放上一个新盘子,函数结束时就取走最上面的盘子。因此,这个"栈"是后进先出的结构。

2. 函数栈帧的创建过程

当函数被调用时,会经历以下几个步骤来创建一个新的栈帧:

  1. 保存返回地址:当前函数执行到一个新的函数调用时,必须知道未来如何返回,因此先把当前指令的返回地址保存到栈中。

  2. 分配局部变量空间:为函数的局部变量分配内存。所有的局部变量都在栈帧中保存,直到函数调用结束。

  3. 保存寄存器内容(可选):在有些情况下,程序会保存一些重要寄存器的内容,以防止新函数修改它们。

  4. 传递参数:把需要传递给被调用函数的参数放入栈中。参数通常从右到左入栈,以保证函数的第一个参数在栈顶。

下图展示了函数调用时的栈帧结构:

 3. 函数栈帧的销毁过程

当函数执行结束并返回时,栈帧会被销毁。销毁的过程通常如下:

  1. 恢复寄存器内容:从栈中恢复被保存的寄存器,以确保返回后系统状态与调用前保持一致。

  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 返回时,栈帧被弹出,这样就确保每次函数的局部变量和状态相互隔离,不会相互影响。

 复盘

  1. 栈帧是用来管理函数调用的机制,每个函数调用都会创建一个栈帧来保存其状态(局部变量、参数、返回地址等)。

  2. 栈是后进先出(LIFO)结构,每次调用函数时都会增加栈帧,返回时会销毁栈帧。

  3. 通过栈帧,程序可以实现递归和嵌套调用,并确保函数之间不会相互干扰。

共勉 💪

同为未来的it人让我们在共同进步吧。

我很喜欢雷军的一段话:我们就悄悄的干,就算失败了咱也不丢人。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值