高校网站首页设计,管理系统 网站模板,专做外贸的网站有哪些资料,网页编辑排版工具有哪些【手把手带你搞定】函数栈帧的创建和销毁 栈帧寄存器一些调试准备调试过程相信在前期C语言的学习的时候,大家一定都有下面这些困惑。
那么今天我们用这篇文章一次性解决以下所有问题: 局部变量是怎么创建的?为什么局部变量的值是随机值?函数是怎么传参的?传参的顺序是怎样… 【手把手带你搞定】函数栈帧的创建和销毁 栈帧寄存器一些调试准备调试过程 相信在前期C语言的学习的时候,大家一定都有下面这些困惑。
那么今天我们用这篇文章一次性解决以下所有问题: 局部变量是怎么创建的?为什么局部变量的值是随机值?函数是怎么传参的?传参的顺序是怎样的?形参和实参是什么关系?函数调用是怎么做的?函数调用结束后怎么返回的? 其实这些问题都离不开一个关键:
函数栈帧的创建和销毁,因为局部变量和函数的调用都是在栈区上创建的。
所以,
== 弄明白函数栈帧的创建和销毁 = 修炼了自己的内功 ==
不仅一次性解决上面的所有问题,而且后期学习更多知识也能更快更好吸收。
注意:在不同的编译器下,函数调用的过程中栈帧的创建是略有差异的,但是大体的逻辑是一样的。
今天我们还是在VS2019的环境下进行学习和观察。
当然,这里推荐使用VS2013的版本进行观察,因为越高级的版本,编译器内部的优化越多,则后台的操作就会越复杂,越不利于我们把函数栈帧的创建与销毁这一过程抽离出来。(后面你就知道了……)
所以,以下如果有一些地方是在VS2019中看不到的,我会把在VS2013中的结果告诉大家作补充;或者有一些地方VS2019比VS2013复杂的地方,我就简单带过啦~
栈帧
什么是栈帧?
寄存器
什么是寄存器? 在编译器中,我们经常可以见到下面这些寄存器: eax、ebx、ecx、edx、ebp、esp 下面,我们要重点关注的是ebp、esp这2个寄存器。
在函数栈帧中,ebp、esp这2个寄存器中存放的是地址,而这两个地址就是用来维护函数栈帧的。
首先,我们知道,每一次函数调用时,程序都要在栈区中为这个函数开辟一块空间。而ebp和bsp就是用来维护这块空间的。
我们用一段代码来举例: 那么在栈区中,程序就为main函数开辟了一块空间,这块空间就是main函数的函数栈帧。
而寄存器ebp中的地址始终指向当前正在调用的函数的栈帧的底部。
寄存器esp则始终指向函数栈帧的顶部。 从以上,我们大概可以清楚esp和ebp是其实就是用来划定当前程序调用的函数的栈帧范围的。
当前程序在调用哪个函数,esp和ebp就分别指向这个函数栈帧的顶部和底部。
所以他们又分别被称为栈顶指针和栈底指针。
当程序调用新的函数,需要开辟新的空间时,就会通过esp和ebp的向上移动来使用新的空间。 一些调试准备
下面我们通过上面这段程序的代码来进行了解。
首先我们进入调试,打开调试窗口中的调用堆栈。 其实,在C语言中,main函数是程序执行的入口,所以,在实行我们的代码之前,程序首先要调用main函数。
那么main函数是被谁调用的呢?
因为在VS2019的环境中,main函数的调用比较复杂,所以我们在直接调用堆栈中看不到是谁调用的。
但是在VS2013的环境下,如果我们再按下F10,就能看到其实main函数是被一个叫__tmainCRTStartup的函数调用的,而这个函数又是被mainCRTStartup函数调用的。
所以,在调用main函数之前,栈区中应该已经为这两个函数分别开辟了空间。 所以,在调用main函数之前,栈区中应该是这样的: