文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C语言超详细讲解函数栈帧的创建和销毁

2024-04-02 19:55

关注

1、本节目标

C语言绝命七连问,你能回答出几个?

想要对上面的这六个问题做出准确深入的回答,我们需要学习函数栈帧的创建和销毁相关知识,在正式进入函数栈帧之前,我们还需要了解一些相关的寄存器和汇编指令。

2、相关寄存器

3、相关汇编指令

4、什么是函数栈帧

函数栈帧(stack frame)就是函数调用过程中在程序的调用栈(call stack)所开辟的空间,这些空间是用来存放:

同时,每一次函数调用,编译器都会为该函数分配一块空间,而这块空间就被称为这个函数的函数栈帧;并且,这块空间是由两个寄存器来维护的:esp寄存器(记录栈顶的地址)和ebp寄存器(记录栈底的地址)。

5、什么是调用堆栈

函数调用堆栈是反馈函数调用逻辑的。我们以main函数的调用为例:

我们可以看到,mainCRTStartup调用__scrt_common_main,__scrt_common_main调用__scrt_common_main_seh,__scrt_common_main_seh调用_SCRT_STARTUP_MAIN,_SCRT_STARTUP_MAINmain,main调用Add。

6、函数栈帧的创建和销毁

我们以一段程序为例讲解函数栈帧:(注意: 函数栈帧的创建和销毁过程,在不同的编译器上实现的方法和细节会有所差异,一般来说,越新的编译器对函数栈帧的封装就越严密,本次演示以VS2019为例。)

演示代码

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

(1)、main函数栈帧的创建与初始化

(2)、main函数的核心代码

(3)、Add函数的调用过程

F11进入Add函数内部,观察Add函数的反汇编代码

代码执行到Add函数的时候,就要开始创建Add函数的栈帧空间了。

在Add函数中创建栈帧的方法和在main函数中是相似的,在栈帧空间的大小上略有差异而已。

1. 将main函数的 ebp 压栈。

2. 计算新的 ebp 和 esp。

3. 将 ebx , esi , edi 寄存器的值保存。

4. 计算求和,在计算求和的时候,我们是通过 ebp 中的地址进行偏移访问 到了函数调用前压栈进去的参数,这就是形参访问。

5. 将求出的和放在 eax 寄存器中准备带回。

(4)、Add函数栈帧的销毁

当函数调用要结束返回的时候,前面创建的函数栈帧也开始销毁,具体销毁过程如下:

(5)、调用完成

调用完Add函数,回到main函数的时候,继续往下执行,可以看到:

00BE185D add esp,8 esp直接+8,相当于跳过了main函数中压栈的a’和b’。

00BE1860 mov dword ptr [ebp-20h],eax 将eax中值,存档到ebp-0x20的地址处,其实就是存储到main函数中ret变量中,而此时eax中就是Add函数中计算的x和y的和,可以看出来,本次函数的返回值是由eax寄存器带回来的。程序是在函数调用返回之后,在eax中去读取返回值的。

7、对开篇问题的解答

当我们完整的了解了函数栈帧创建和销毁的过程后,我们就可以回答开篇提到的问题了:

1.局部变量是如何创建的?

局部变量的创建是在局部变量所在的函数的栈帧创建完成并初始化后,然后在该栈帧内为局部变量分配空间的。

2.为什么局部变量不初始化其内容是随机的?

因为编译器在创建函数栈帧后会在栈帧空间里面放入一个值,而这个值是随机的。

3.有些时候屏幕上输出的"烫烫烫"是怎么来的?

因为main函数调用时,在栈区开辟的空间的其中每一个字节都被初始化为0xCC,而如果我们定义的是一个未初始化的数组,且这个数组恰好在这块空间上创建,因为0xCCCC(两个连续排列的0xCC)的汉字编码是“烫”,所以屏幕上输出的就是烫烫烫。

4.函数调用时参数时如何传递的?传参的顺序是怎样的?

我们在调用函数之前,就会在栈顶上从右向左依次压入需要传递的参数,在创建好被调函数的函数栈帧后通过指针的偏移量来使用传递过去的参数,而不是在被调函数的函数栈帧内创建形参。

5.函数的形参和实参的关系是什么?

形参是实参的一份临时拷贝,二者的存储位置不同,形参的改变不会影响实参。

6.函数的返回值是如何带回的?

函数的返回值通过eax寄存器带回。

7.函数是怎样在栈区上开辟和释放空间的?

函数通过改变esp和edp的指向来创建和销毁空间,空间销毁并不会清除该空间中的数据,下一次使用该空间时新数据直接覆盖原数据即可。

到此这篇关于C语言超详细讲解函数栈帧的创建和销毁的文章就介绍到这了,更多相关C语言函数栈帧内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯