返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言超详细讲解函数栈帧的创建和销毁
  • 137
分享到

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

2024-04-02 19:04:59 137人浏览 安东尼
摘要

目录1、本节目标2、相关寄存器3、相关汇编指令4、什么是函数栈帧5、什么是调用堆栈6、函数栈帧的创建和销毁(1)、main函数栈帧的创建与初始化(2)、main函数的核心代码(3)、

1、本节目标

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

  • 局部变量是如何创建的?
  • 为什么局部变量不初始化其内容是随机的?
  • 有些时候屏幕上输出的"烫烫烫"是怎么来的?
  • 函数调用时参数时如何传递的?传参的顺序是怎样的?
  • 函数的形参和实参的关系是什么?
  • 函数的返回值是如何带回的?
  • 函数是怎样在栈区上开辟和释放空间的?

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

2、相关寄存器

  • eax:通用寄存器,保留临时数据,常用于返回值。
  • ebx:通用寄存器,保留临时数据。
  • ebp:栈底寄存器,用来记录栈底的地址。
  • esp:栈顶寄存器,用来记录栈顶的地址。
  • eip:指令寄存器,保存当前指令的下一条指令的地址。

3、相关汇编指令

  • mov:数据转移指令。
  • sub:减法命令。
  • add:加法命令。
  • push:数据入栈,同时esp栈顶寄存器也要发生改变。
  • pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变。
  • call:函数调用,1. 压入返回地址 2. 转入目标函数。
  • jump:通过修改eip,转入目标函数,进行调用。
  • lea:传递地址指令,用于加载有效地址。
  • ret:恢复返回地址,压入eip,类似pop eip命令。

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语言函数栈帧内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C语言超详细讲解函数栈帧的创建和销毁

本文链接: https://lsjlt.com/news/148010.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C语言超详细讲解函数栈帧的创建和销毁
    目录1、本节目标2、相关寄存器3、相关汇编指令4、什么是函数栈帧5、什么是调用堆栈6、函数栈帧的创建和销毁(1)、main函数栈帧的创建与初始化(2)、main函数的核心代码(3)、...
    99+
    2024-04-02
  • C语言函数栈帧的创建和销毁详解
    目录写在前面Add函数的调用函数传参Add函数栈帧的创建Add函数栈帧的销毁main函数栈帧的销毁总结写在前面 我们知道,每一次函数调用都需要在栈区上为其开辟一块空间,这块空间就叫做...
    99+
    2024-04-02
  • C语言函数栈帧的创建与销毁详解
    目录前言一、函数栈帧是什么?1.寄存器2.ebp与esp二、函数栈帧的创建1.代码块2.调用堆栈3.esp与ebp如何维护栈帧总结 前言 大家在学习的时候一定有以下困惑: ...
    99+
    2024-04-02
  • c语言函数栈帧的创建和销毁过程详解
    目录1 相关知识介绍 1.1 寄存器1.2 函数栈帧概述2 栈帧创建与销毁过程1 相关知识介绍  1.1 寄存器 一般计算机内通用寄存器包括eax,ebx,ec...
    99+
    2024-04-02
  • C语言函数栈帧如何创建和销毁
    这篇文章主要为大家展示了“C语言函数栈帧如何创建和销毁”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C语言函数栈帧如何创建和销毁”这篇文章吧。写在前面我们知道,每一次函数调用都需要在栈区上为其开...
    99+
    2023-06-29
  • C语言函数栈帧的创建和销毁介绍
    在初学c语言中,很多时候要记的内容有点多,有时候并不能深入的了解它。关于函数的栈帧可以帮助我们深入了解函数传参的过程,让我们了解c语言。 以下是我们平时接触过,但不了解的问题: 1...
    99+
    2024-04-02
  • C语言详尽图解函数栈帧的创建和销毁实现
    目录常见寄存器基本的汇编语言知识具体实现关于栈帧创建与销毁的问答题注:本文章所使用的编译器是VS2010,由于不同编译器的函数栈帧与销毁略有差异,所以具体细节请读者自行实践! 常见寄...
    99+
    2024-04-02
  • C语言函数栈帧的创建与销毁原理图解
    目录什么是函数栈帧什么是栈?与函数栈帧有关的汇编语句函数如何创建栈帧并销毁main函数栈帧开辟调用Add函数返回主函数什么是函数栈帧 我们在写C语言代码的时候,经常会把一个独立的功能...
    99+
    2024-04-02
  • C语言中函数栈帧的创建和销毁的深层分析
    目录一、本文目标二、基础知识1、寄存器2、代码案例  3、总体栈帧概况4、所需反汇编代码总览三、函数栈帧创建销毁过程1、_tmainCRTStartup函数(调用main函...
    99+
    2024-04-02
  • 如何进行C语言函数栈帧的创建和销毁分析
    如何进行C语言函数栈帧的创建和销毁分析,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。以下是我们平时接触过,但不了解的问题:1.为什么局部变量在未赋值前是随机的。2.局部变量...
    99+
    2023-06-22
  • C语言超详细解析函数栈帧
    目录一、前面二、预备知识三、栈帧创建与销毁四、总结一、前面 本章将以汇编视角看函数栈帧的内存是如何使用与回收的,为了降低汇编语言的理解成本,以图示的方式讲解每一步汇编指令所带来的效果...
    99+
    2024-04-02
  • 详细理解函C语言的函数栈帧
    目录一、函数栈帧的创建1.寄存器2.函数栈帧3.函数中调用函数二、函数栈帧的销毁总结一、函数栈帧的创建 1.寄存器 一般来说,计算机中的寄存器有六种 分别是:eax, ebx, e...
    99+
    2024-04-02
  • C语言函数栈帧详解
    目录前言一.函数栈帧是什么?二、栈帧准备知识1.内存分区2.什么是栈?三、详解栈帧创建与销毁全过程调用函数之前:将传入函数的值放入栈中函数执行:1.保护当前ebp2.创建所需调用函数...
    99+
    2024-04-02
  • C语言超详细讲解库函数
    目录1 返回整数的getchar函数2 更新顺序文件3 缓冲输出与内存分配4 库函数练习1 返回整数的getchar函数 代码: #include<stdio.h> ...
    99+
    2024-04-02
  • C语言函数超详细讲解上篇
    目录前言1、函数是什么?2、C语言中函数的分类2.1 库函数2.1.1 如何学会使用库函数2.1.2 自定义函数3、函数的参数3.1 实际参数(实参)3.2 形式参数(形参)4、函数...
    99+
    2024-04-02
  • C语言函数超详细讲解下篇
    目录前言函数的声明和定义函数声明函数定义举例简单的求和函数把加法单独改写成函数添加函数声明带头文件和函数声明静态库(.lib)的生成静态库文件的使用方法函数递归什么是递归?递归的两个...
    99+
    2024-04-02
  • C语言超详细讲解getchar函数的使用
    目录一、getchar 函数二、缓冲区1、什么是缓冲区2、为什么要存在缓冲区3、缓冲区的类型4、缓冲区的刷新三、getchar 函数的正确使用1、getchar 的换行问题2、get...
    99+
    2024-04-02
  • C语言超详细讲解栈的实现及代码
    目录前言栈的概念栈的结构栈的实现创建栈结构初始化栈销毁栈入栈出栈获取栈顶元素获取栈中有效元素个数检测栈是否为空总代码Stack.h 文件Stack.c 文件Test.c 文件前言 栈...
    99+
    2024-04-02
  • C语言超详细讲解字符串函数和内存函数
    目录字符串函数长度不受限制的字符串函数strlenstrcpystrcatstrcmp长度受限制的字符串函数介绍strncpystrncatstrncmp字符串查找以及错误报告str...
    99+
    2024-04-02
  • C语言超详细讲解函数指针的运用
    目录前言计算器的例子回调函数转移表前言 前面我们学习了各种各样的指针类型,有些指针可以说是稀奇百怪,特别是函数指针,有些朋友可能觉得,函数指针有些多余,调用函数为什么要用指针调用,直...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作