C | 函数栈帧的创建与销毁


目录

  • 前言
  • 函数栈帧的创建与销毁
    • 寄存器
    • 函数栈帧
    • 内存使用示意图
    • 被调用的main函数
    • 一些反汇编代码的解释
    • 过程分析
  • 结语

前言 在我们刚开始学习C语言的时候,相信小伙伴们和我一样有很多的困惑吧?
比如:
局部变量是怎么创建的?
为什么局部变量的初始值是随机值?
函数是怎么传参的?
函数传参的顺序是怎么样?
形参和实参有什么关系?
为什么说形参是实参的一份临时拷贝?
函数调用的过程是怎么实现的?
函数调用结束后是怎么返回的?
别着急,今天就让我们一起来学习一下函数栈帧的创建与销毁。
相信通过今天的内容,小伙伴们对以上的困惑会得到答案。
重要的话放在前面:由于我所了解到的知识还不够深入,难免会有说的不当的地方,如有说错,请各位大佬指出!
函数栈帧的创建与销毁 寄存器 首先,我们需要了解一个概念:寄存器。
常见的寄存器有:
eax
ebx
ecx
edx
ebp
esp
寄存器并不是在内存中的,而是集成在CPU中,函数栈帧的创建与销毁和寄存器有密切的关系。
函数栈帧 函数栈帧就是在内存的栈区中,为函数调用而开辟的一块内存空间
而ebp和esp这两个寄存器是用来存放地址的,这两个地址就是用来维护函数栈帧的。
内存使用示意图 内存的使用大致如下:
C | 函数栈帧的创建与销毁
文章图片

被调用的main函数 再C程序中,我们知道main是程序的入口,一个程序只能有一个入口,但是,其实main函数也是被别的函数调用的。只不过这些过程被编译器封装起来了,我们不易观察而已。而且,版本越高的编译器越不容易观察这一过程。
以VS2013编译器为例,我们再调试的时候,可以鼠标右键进入反汇编,然后不断按下F10,看程序的执行过程。
当我们执行到main函数最后一行的时候,再按F10会看到,其实mains函数是被_tmainCRTStartup这个函数调用的。
C | 函数栈帧的创建与销毁
文章图片

C | 函数栈帧的创建与销毁
文章图片

【C | 函数栈帧的创建与销毁】C | 函数栈帧的创建与销毁
文章图片

到这里,其实我们需要知道,main也是被别的函数调用的即可。而main函数被调用的时候,也会开辟一块属于自己的函数栈帧。
C | 函数栈帧的创建与销毁
文章图片

一些反汇编代码的解释 mov :数据传送指令,把数据传送到指定的地址,从右往左传送
sub:减法指令,把地址进行减法运算
push:实现压入操作的 (压栈,即给栈顶放入一个元素)
pop:实现弹出操作的指令(出栈,即给栈顶拿出一个元素)
call:用于保存当前指令的下一条指令并跳转到目标函数
过程分析 我们已下面代码为例,来分析函数栈帧的创建与销毁的过程。
#include int Add(int a, int b) { int c = 0; c = a + b; return c; }int main() { int a = 15; int b = 25; int c = Add(a, b); printf("%d", c); return 0; }

esp:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。 (栈顶指针)
bp:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。 (栈底指针)
由于每次开辟新的栈帧都是使用低地址,而这一过程再内存图中形象的成为”压栈“。
C | 函数栈帧的创建与销毁
文章图片

C | 函数栈帧的创建与销毁
文章图片

C | 函数栈帧的创建与销毁
文章图片

函数栈帧的创建,主要就是ebp和esp这两个指针压栈而形成,当这两个指针出栈的时候,函数栈帧也就销毁了。
当函数传参的时候,是在调用函数前就已经为参数开辟好空间,所以说形参是实参的一份临时拷贝。
函数的返回值是通过寄存器的方式返回的的。
当调用另外的函数的时候,寄存器会记录下当前的位置,并让ebp和esp指向新的空间。
而这基本就是函数栈帧的创建与销毁的过程。
结语 其实这些知识也是我不太懂的,也是希望写一篇博客来加深我对这些知识的理解,如果有错误的地方,还希望大佬们指出!!
最后,创作这篇文章太不容易啦,我也是找了很多资料
希望大伙儿可以点个关注、给一个赞在给一个评论哦~
十分感谢大家的支持!!
C | 函数栈帧的创建与销毁
文章图片

    推荐阅读