4.12 函数栈帧的销毁与创建

这块知识还是比较难的,bilibili 有 @九曲阑干 更新的视频可以看看

阅读更多:

https://zhuanlan.zhihu.com/p/559406375

https://xie.infoq.cn/article/3a8c79d7daf180e380700f316

4.12.1 提出问题

注意: 内存中的栈和数据结构中的栈不是一个东西。

提出问题,这些问题我在学习C语言的时候,确实没有去想:

  • 局部变量 int a 是怎么创建的?

  • 如果不对 a 进行初始化,a 的值是多少?

  • 函数是如何被调用的?

  • 函数的参数是如何传递的?

  • 函数的返回值又是什么样子?

4.12.2 函数栈帧的概念

函数栈帧(Function Stack Frame)是计算机编程中一个与函数调用和执行相关的概念。它通常包含了以下几个要素:

  1. 函数参数(Function Arguments):这是传递给函数的值,函数可以使用这些参数来执行特定的任务。

  2. 局部变量(Local Variables):函数内部定义的变量,用于存储临时数据和计算结果。这些变量通常只在函数内部可见。

  3. 返回地址(Return Address):函数执行完毕后,需要返回到调用它的地方,返回地址指示了程序执行的下一个步骤。

  4. 栈指针(Stack Pointer):一个指针,指向函数栈帧的栈顶。栈用于存储函数调用的上下文信息,栈指针用于跟踪当前栈顶的位置。

  5. 其他控制信息:可能包括函数的状态、寄存器的值以及其他执行上下文信息。

函数栈帧通常在函数被调用时创建,用于维护函数的执行环境。每当函数被调用,一个新的函数栈帧就被压入函数调用栈(Call Stack)中。当函数执行完毕,函数栈帧被弹出,程序返回到前一个函数的上下文。

这个概念非常重要,因为它允许程序在执行多个嵌套函数调用时,能够正确地管理函数的局部变量、参数和执行流程。函数栈帧的创建和销毁是编程语言和计算机体系结构的基本组成部分,用于实现函数的递归调用、错误处理和程序的控制流程。

每一次函数调用,操作系统都会在内存的栈区上开辟一块空间,称为栈帧。

函数调用 >> 建立栈帧 >> 栈帧存储局部变量、参数等

4.12.3 内存栈区的特性

  • eps 是 栈顶

  • ebp 是 栈底

内存的栈区两个特性: 先进后出,后进先出。

4.12.4 常见的寄存器

常见的寄存器通常是指CPU内部的一组特殊寄存器,用于存储数据、地址和控制信息。这些寄存器在计算机程序的执行中起着重要的作用,特别是在函数调用和返回时,它们与函数栈帧之间有紧密的关系。以下是一些常见的寄存器及它们与函数栈帧的关系:

  1. 栈指针寄存器(Stack Pointer Register,通常简称为SP):SP寄存器存储着当前栈的顶部地址,它指向栈中最近压入的数据。在函数调用时,栈指针通常会移动以分配空间用于函数的局部变量和保存返回地址等。函数栈帧中的局部变量通常相对于SP寄存器来分配和访问。

  2. 基址指针寄存器(Base Pointer Register,通常简称为BP):BP寄存器用于建立函数的堆栈帧。它通常指向当前函数的堆栈帧的基址,这个基址在函数内可以用来访问函数参数和局部变量。函数栈帧的创建和销毁通常会涉及到BP寄存器的设置和恢复。

  3. 程序计数器寄存器(Program Counter Register,通常简称为PC):PC寄存器存储着当前正在执行的指令的地址,它用于跟踪程序的执行位置。在函数调用和返回时,PC寄存器被用来跳转到目标函数的入口和返回到调用函数。

下面是一个简单的C语言代码示例,以说明这些寄存器与函数栈帧的关系:

#include <stdio.h>

void foo(int x, int y) {
    int result = x + y;
    printf("Result: %d\n", result);
}

int main() {
    int a = 5;
    int b = 3;
    foo(a, b);
    return 0;
}

在上述示例中,main 函数和 foo 函数都涉及到函数栈帧的创建和使用。当 main 函数调用 foo 函数时,它需要将参数 ab 压入栈中,然后调整栈指针寄存器(SP)来分配局部变量 result 的空间。BP寄存器通常用来建立当前函数的堆栈帧,并且在函数返回时用于恢复栈指针。

总之,寄存器在函数调用和返回过程中起到重要的作用,帮助管理参数、局部变量和返回地址等信息。函数栈帧是函数在堆栈中的分配的一块内存空间,用于保存这些信息。以上示例仅为简单示例,实际的实现会根据具体的体系结构和编译器有所不同。

Last updated