函数栈帧的创建与销毁,带你了解代码底层原理

本文深入探讨了C语言中函数调用的过程,包括局部变量的创建、初始值、参数传递和函数返回。通过示例代码和反汇编分析,揭示了ebp和esp寄存器在维护栈帧中的作用,以及形参与实参的关系。同时,介绍了函数调用时栈帧的创建和销毁,帮助理解函数执行的底层机制。
摘要由CSDN通过智能技术生成

在学习C语言时,我们难免有许多疑问
例如:
(1)局部变量是怎么创建的?
(2)为什么局部变量的值是随机的?
(3)函数是怎么传参的?传参的顺序如何?
(4)形参和实参是什么关系?
(5)函数调用是怎么做的?
(6)函数调用结束后是怎么返回的?

这些疑问其实都和函数栈帧的创建与销毁有关

寄存器

eax,ebx,ecx,edx,ebp,esp等都属于寄存器

ebp与esp 这两个寄存器放的是地址,这两个地址用来维护函数栈帧的,每一次函数调用都要在栈区上开辟一块空间
在这里插入图片描述

在VS2013中main函数被__tmainCRTStartup所调用

在这里插入图片描述

以下面代码做为研究:

#include<stdio.h>
int Add(int x, int y) {
	return x + y;
}
int main() {
	int a = 10;
	int b = 20;
	int c = Add(a, b);
	printf("%d", c);
	return 0;
}

按f10进入调试,右键进入反汇编

在这里插入图片描述

如下图:(如果显示的是符号,可以右键将符号去掉)

在这里插入图片描述
在这里插入图片描述

接着我们开始逐条执行,此时ebp和esp分别存放两个地址

在这里插入图片描述

这两个寄存器存的地址便是__tmainCRTStartup函数所压的栈

在这里插入图片描述

随着代码的执行,esp会指向ebp所存地址

在这里插入图片描述

此时esp进行减法

在这里插入图片描述

地址变化如下:

在这里插入图片描述

相当于为main函数预开辟一段空间,执行如下图所示:

在这里插入图片描述
在这里插入图片描述

接下来的三步push相当于压了三次栈

在这里插入图片描述
在这里插入图片描述

接下来几步相当于将main函数中全部初始化为CCCCCCCC

在这里插入图片描述

然后接着执行

在这里插入图片描述

这步的意思是将a放在ebp-8的位置

在这里插入图片描述
此处即是为a开辟的空间,所以当a未初始化时,a放的便是CCCCCCCC,所以为随机值

在这里插入图片描述

创建的a和b在内存中便如上图一样存放

接着,代码调用Add函数
在这里插入图片描述

此时,我们可以观察到,用eax来存ebp-14h以及用ecx来存ebp-8的地址,而ebp-14h和ebp-8分别是b和a的地址

在这里插入图片描述

调用之后压栈如上图

执行到call这步后,按f11进入所调用函数内部
在这里插入图片描述

函数内部如下

在这里插入图片描述

然后我们可以观察到,调用的Add函数前半部分和main函数的初始化一样,为Add函数的准备工作,而第一条语句的push相当于将原来压在main函数的ebp压在Add上

在这里插入图片描述

接下来几条语句便是Add函数的栈帧

在这里插入图片描述

执行完前面语句后,x,y呢?

在这里插入图片描述

这两条语句我们看到,在需要x和y时,我们找到了ebp+8和ebp+0Ch

在这里插入图片描述

而此时ebp+8和ebp+0Ch恰好表示ecx和eax,即存放的a和b,所以形参不是在Add函数内部创建的,而是在寄存器中找的

函数的传参是在函数创建之前就已经压栈了,所以我们说形参是实参的一份临时拷贝,所以改变形参并不会影响实参

在这里插入图片描述

当函数执行到此处时,弹出edi,esi和ebx,然后将ebp地址赋给esp,即销毁掉Add函数

热门文章:
AI三子棋,极大极小值算法
扫雷游戏
DP动态规划

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ja_King_ZH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值