hello 大家好!我们又见面了。今天我们一起来学习C语言中的函数栈帧的创建和销毁部分,希望您能花点您宝贵的时间,让我们一起学习和提高,有点小激动呢?有木有?
首先,大家可以思考以下一些问题,看大家是否存在疑惑?
1.函数的局部变量是如何创建的?
2.为什么局部变量的值是随机值?
3.函数是如何传参的?传参的顺序是怎样的?
4.形参和实参是什么关系?
5.函数调用是如何做的?
6.函数调用结束后是如何返回的?
学完本文,你将豁然开朗
**注意:**本次使用的是VS2013,不同的编译器略有差异,具体细节取决于编译器的实现。
首先给大家介绍一下寄存器,寄存器是一种存储设备,它是集成到CPU上的,eax,ebx,ecx,edx,ebp,esp等都是寄存器,其中ebp,esp,这2个寄存器存放的是地址,这2个地址是用来维护函数栈帧的。
每一个函数调用,都会在栈区为其创建一个空间,即函数栈帧。
我们写一个比较简单的函数,Add函数,带大家分析,方便大家理解。
#include
int Add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 10;
int b = 20;
int c = 0;
c = Add(a, b);
printf("%d\n", c);
return 0;
}
main函数是被其他函数调用的吗?大家应该会说不是,但实际是怎样的呢?
通过此我们发现main函数被__tmainCRTStartup函数调用,__tmainCRTStartup函数又被mainCRTStartup函数调用。
将上面代码转成汇编语言如下,接下来我将带大家一一分析,通过汇编代码理解其实质。
看着是不是有点多,别慌,往下继续学。
函数是如何调用的,main函数的调用。
__tmainCRTStartup函数调用main函数时,栈区为其分配空间,那么如何为其分配空间的呢,将ebp进行压栈,在将esp的值赋给ebp,esp的值sub为esp-0E4h,在将ebx,esi,edi,进行压栈,led(load effective address),从地址ebp-0E4h往下39h的空间,次数,全部初始化成cccccccc,此时main函数的栈帧分配完成。
从这可以看出局部变量是在其函数的栈区内找一块空间,没有赋值时,它为随机值,具体随机值是啥,取决于编译器,这里时cccccccc
将显示符号名取消勾选之后,汇编代码如下:
此时已将局部变量的值初始化了。
进入Add函数时,先进行传参,Add(a,b),由上可知,传参顺序是由右往左,即从b到a,main函数传参是通过将a,b进行压栈,可以理解为形参a,b在main函数的函数栈帧内。
形参和实参是什么关系?我们可以知道形参是实参的临时拷贝,形参的改变不会影响实参。
此时调用Add函数,跟main函数前期操作一样,不做过多解释。
接下来 函数调用结束后是如何返回的?
而后进行Add函数的销毁,结果如下:
码字不易,希望能帮助到大家,可以点一个赞吗?哈哈,评论和收藏支持一下哦,感谢大家!期待再次相见!