【C语言】函数栈帧的创建和毁销

这篇具有很好参考价值的文章主要介绍了【C语言】函数栈帧的创建和毁销。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

大家好,我是深鱼~

目录

一、寄存器

二、栈区

 三、函数栈帧的创建

1.为main函数开辟栈帧 

2.在main函数中创建变量

3.调用Add函数前的准备

 4.为Add函数开辟栈帧

 5.在Add函数中创建变量并运算

四、函数栈帧的销毁

6.Add函数栈帧的销毁

7.返回main函数栈帧


【前言】前期学习的时候,我们可能有很多的困惑

比如:

·局部变量是怎么创建的呢?

·为什么局部变量的值是随机值?

·函数是怎么传参的?传参的顺序是怎么样的?

·形参和实参是什么关系?

·函数调用是怎么做的?

·函数调用是结束后怎么返回的?

知道了函数栈帧的创建和销毁这些问题就都可以解决了,学习这个知识其实就是修炼自己的内功,也能搞懂后期的更多知识

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

 【进入正题】:

本部分讲解使用的环境是vs2013,因为越高级的编译器,越不容易学习和观察。

同时在不同的编译器下,函数调用过程中栈帧的创建是略有差异的,具体细节取决于编译器的实现

一、寄存器

电脑中的任何指令都是在CPU上运行的,但是CPU本身只负责运算不负责存储,数据一般都存储在内存和寄存器(存储最常见的数据

寄存器有eax,ebx,ecx,edx,还有本篇的重点ebp,esp

ebp(栈底指针),esp(栈顶指针)这2个寄存器中存放的是地址,这两个地址是用来维护函数栈帧的

二、栈区

每一个函数调用,都要在栈区创建一个空间

那么什么是栈区呢?

内存四区模型:【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

栈区stack:由编译器自动分配和释放,存放函数的参数值(形参和返回值),局部变量的值

栈区的使用习惯是先使用高地址,再使用低地址,空间不断向上消耗,如果再使用空间,就需要在顶部放数据(栈顶),当函数调用时,esp维护的就是栈顶ebp维护的就是栈底

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

【温馨提示】:这里只是以main函数开辟的空间为例,esp,ebp不只是维护main函数,还有其他的函数

【问】:那么什么又是栈帧呢? 

 【栈帧】:利用寄存器访问局部变量,函数的参数值等的手段,表示程序的函数调用记录

【补充】:压栈和出栈是什么?

push:压栈:从栈顶上放入元素

pop:出栈:从栈顶上删除元素 

 三、函数栈帧的创建

代码:为了更清晰地演示此过程,所以代码写的足够的细节

#include<stdio.h>
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;
}

按下F10进行逐过程调试,按F11下一步,然后打开调试-窗口-调用堆栈,随着我们一步一步地按F11逐语句调试,最后发现从return 0跳转到另一个界面,其实就是main函数的调用函数

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法 其实main()函数是被_tmainCRTStartup函数调用,而_tmainCRTStartup函数又是被mainCRTStartup函数调用的

接下来分步骤演示函数栈帧的创建和销毁的过程

1.为main函数开辟栈帧 

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

<0>在调用main函数之前:esp和ebp分别在栈顶和栈底维护_tmainCRTStartup函数

<1>:将ebp的值压入栈中,esp的值向低地址减小,指向esp的上端

<2>:将esp的值赋给ebp,两者同时指向esp                         

<3>:将esp减去0E4h并保存在esp中,即esp向低地址移动0E4h个字节(就是开始为main函数开辟空间) 

<4>:将ebx,esi,edi的值分别压入栈中,注意每次压栈后,esp都会向低地址移动,最后sep就到达了edi的上方

<5>:将ebp减去0E4h的地址放到到edi中(lea:load effective address)

                      将39h放到ecx中去

                      将0CCCCCCCCh放到eax中去

<6>:将从edi(ebp-0E4h)开始的位置,重复39h次地向下(高地址方向)的内存赋值0CCCCCCCCh,每次赋值双字符(dword:double word)即四字节的空间(就是为main函数开辟的空间全部初始化为0CCCCCCCCh)

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法
为main()函数开辟栈帧

                                                                                                                              

2.在main函数中创建变量

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

将初始化的值赋值给内存地址为【 】中的双字符空间

eg:int a=10:将0Ah(也就是初始化的值10)放到ebp-8为内存地址的空间

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

 结果我们可以看到三个位置分别放入了变量并初始化了,从这里我们就可以知道为什么变量不初始化就是随机值了,因为初始化,变量里面就是0CCCCCCCCh,这个值是不确定的 

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

3.调用Add函数前的准备

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

<1>传参b:

(1)把地址为ebp-14h(b的地址)里面的数据(也就是b的值)赋给eax

(2)将eax的值(里面放的就是b的值20)压入栈中,esp向上(低地址)移动

<2>传参a:

(1)把地址为ebp-8(a的地址)里面的数据(也就是a的值)赋给ecx

(2)将ecx的值(里面放的就是a的值10)压入栈中,esp向上(低地址)移动

【注意】传参是从右往左传的

<3>准备调用Add函数:

(1)把call指令的下一条指令的地址压入栈中(这一步是为了调用完自定义函数后根据这个地址回到main函数去,并从这个地址向下执行),esp向上(低地址)移动

【注意】这个时候main函数的栈帧范围:栈顶esp已经到了这个地址,而栈底ebp还在下面

(2)程序进入到Add函数中去

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

 4.为Add函数开辟栈帧

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

 这一步和为main函数开辟栈帧一样

<1>:将ebp的值压入栈中,esp向上(低地址)移动

<2>:将esp的值赋给ebp,两者同时指向esp   

<3>:将esp减去0CCh并保存在esp中,即esp向低地址移动0CCh个字节(就是开始为Add函数开辟空间) 

<4>:将ebx,esi,edi的值分别压入栈中,每次压栈后,esp都会向上(低地址)移动,最后sep就到达了edi的上方

<5>:将ebp减去0CCh的地址放到到edi中

                      将33h放到ecx中去

                      将0CCCCCCCCh放到eax中去

<6>:将从edi(ebp-0CCh)开始的位置,重复33h次地向下(高地址方向)的内存赋值0CCCCCCCCh,每次赋值双字符(四字节)的空间(就是为Add函数开辟的空间全部初始化为0CCCCCCCCh)

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

 5.在Add函数中创建变量并运算

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

<1>创建变量z:将0(z初始化的值)放到ebp-8为内存地址的空间

<2>进行运算:

(1)将地址为ebp+8里面的数据(也就是a)放入eax

(2)将地址为ebp+12里面的数据(也就是b)加到eax(上次的10+这次的20=30)

(3)将eax放入地址为ebp-8里面(也就是z,让z=30)

【注意】形参并不是在自定义函数里面创建的,而是回去找到调用函数之前压栈压进去值的地址

<3>返回z:将地址为ebp-8里面的数据(也就是30)放入eax(让eax读取z的值,防止函数销毁以后拿不回z的值)

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

四、函数栈帧的销毁

6.Add函数栈帧的销毁

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

<1>出栈:edi,esi,ebx分别弹出栈区,每一次出栈esp都向下(高地址)移动

<2>Add函数回收:将ebp的值赋给esp,add函数的栈就没了

<3>将栈顶main函数的ebp弹出,ebp直接回到了main函数的ebp,同时esp向下(高地址)移动4字节

<4>返回ret,程序自动返回刚才call指令的下一行,读完地址,esp又向下(高地址)移动4个字节

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

7.返回main函数栈帧

【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法

 <1>形参x,y空间销毁:esp+8即esp向下(高地址)移动8字节,将形参x,y空间也还给操作系统

<2>把计算结果给c:把eax(Add求和的结果)的值放到以ebp-20h(c的地址)为地址的空间中

 main函数的销毁和Add函数差不多,下面就不做过多的阐述

【总结】

以上就是函数栈帧的创建和销毁,可以看到这个过程非常的严谨,非常的奇妙

看到这里相信大家对前面提出的问题都已经有了答案,有些地方还是挺难理解的,有问题欢迎评论区或者私信交流,觉得笔者写的还可以,或者自己有些许收获的,麻烦铁汁们动动小手,给俺来个一键三连,万分感谢 【C语言】函数栈帧的创建和毁销,开发语言,c语言,算法文章来源地址https://www.toymoban.com/news/detail-621916.html

到了这里,关于【C语言】函数栈帧的创建和毁销的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言——详解函数栈帧的创建和销毁

    为了深入学习C语言,也为了方便理解,我学习了函数栈帧。函数栈帧的创建和销毁能够让我更加深刻的了解编程逻辑和语法。我们学习语法和编程逻辑都是基于封装好的知识上得。因此,我们有必要对函数栈帧的创建和销毁进行学习。本篇博客将用来介绍函数栈帧的创建和销

    2024年02月12日
    浏览(30)
  • C语言-------函数栈帧的创建和销毁------剖析描骨

    🎂        ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂    🎂      作者介绍:                              🎂🎂        🎂 🎉🎉🎉🎉🎉🎉🎉              🎂           🎂作者id:老秦包你会,         🎂 简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂

    2024年02月14日
    浏览(25)
  • C语言之反汇编查看函数栈帧的创建与销毁

    函数栈帧是用于在计算机程序中实现函数调用的一种数据结构。在函数调用过程中,每个函数都需要在内存中创建一个栈帧,用于存储局部变量、返回地址和参数等。 具体来说,函数栈帧通常包含以下部分: 局部变量表:存储函数的局部变量,包括基本数据类型(如整数、

    2024年01月23日
    浏览(30)
  • 【C语言__函数栈帧的创建和销毁__复习篇9】

    目录 前言 一、知识补充 二、分析创建和销毁的过程 三、前言问题回答 本篇主要讨论以下问题: 1. 编译器什么时候为局部变量分配的空间 2. 为什么局部变量的值是随机的 3. 函数是怎么传参的,传参的顺序是怎样的 4. 形参和实参是什么关系 5. 函数调用是怎么做的 6. 函数调

    2024年04月25日
    浏览(28)
  • 打通你学习C语言的任督二脉-函数栈帧的创建和销毁(上)

      🌈个人主页:  Aileen_0v0 🔥系列专栏: C语言学习 💫个人格言: \\\"没有罗马,那就自己创造罗马~\\\" 待解决疑惑: 局部变量是怎么创建的? 为什么局部变量的值是随机值? 函数是怎么传参的?传参的顺序是怎样的? 形参和实参是什么关系? 函数调用是怎么做的? 函数调用是结束后怎么返

    2024年02月05日
    浏览(27)
  • 函数栈帧的创建和销毁

    前言 观察函数栈帧的创建和销毁,不要使用太高级别的的编译器,越高级的编译器越不容易学习和观察。同时在不同编译器下,函数调用的过程中栈帧的创建是略有差异的,具体细节取决于编译器的实现 我们在写C语言代码的时候,经常会把一个独立的功能抽象为函数,所以

    2023年04月17日
    浏览(36)
  • 函数栈帧的创建与销毁

    魔王的介绍:😶‍🌫️一名双非本科大一小白。 魔王的目标:🤯努力赶上周围卷王的脚步。 魔王的主页:🔥🔥🔥大魔王.🔥🔥🔥 ❤️‍🔥大魔王与你分享:莫泊桑说过,生活可能不像你想象的那么好,但是也不会像你想象的那么糟。人的脆弱和坚强都超乎了自己的想

    2024年02月15日
    浏览(30)
  • 从汇编代码探究函数栈帧的创建和销毁的底层原理

    人,只有在放弃战斗的时候才算输,只要坚持战斗,就还没输  本文收录于青花雾气-计算机基础 往期回顾 从0到1搞定在线OJ 数据在内存中的存储 计算机存储的大小端模式 目录 一、先导知识 二、函数调用堆栈 三、函数栈帧的创建 1.创建函数栈帧 2.创建变量 3.函数传参 4.函数

    2024年02月08日
    浏览(27)
  • 探秘函数栈帧:『 揭开函数栈帧创建与销毁的神秘面纱 』

    .. 目录 知识点回顾 一、什么是栈帧(堆栈帧)? 1.内存布局 2.常用寄存器 3.汇编指令 👇👇对于栈的详细介绍 : 👇👇函数栈帧的介绍: 二、函数调用中的栈帧 1.探究main函数栈帧的创建 2.对main函数中的代码进行分析 3.探究Add函数栈帧的创建  三、函数栈帧的销毁过程 博客引

    2024年02月06日
    浏览(38)
  • C语言:函数栈帧

    寄存器: eax ebx ecx edx ebp esp 必须理解这两个寄存器(寄存器是独立于内存的) 这两个寄存器存放的是地址,用来维护函数栈帧(正在调用哪个函数,两个寄存器就维护哪个函数的栈帧) 每一个函数都要创建一个空间(栈区创建,栈区的使用是先使用高地址,后使用低地址)

    2024年02月07日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包