9.为什么有时候会“烫烫烫”——之函数栈桢

目录

1. 什么是函数栈帧

2. 理解函数栈帧能解决什么问题呢?

3. 函数栈帧的创建和销毁解析

3.1 什么是栈?

3.2 认识相关寄存器和汇编指令

3.3 解析函数栈帧的创建和销毁

小知识:烫烫烫~

Q&A


1. 什么是函数栈帧

我们在写C语言代码的时候,经常会把一个独立的功能抽象为函数,所以C程序是以函数为基本单位的。 那函数是如何调用的?函数的返回值又是如何待会的?函数参数是如何传递的?这些问题都和函数栈帧 有关系。

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

  • 函数参数和函数返回值
  • 临时变量(包括函数的非静态的局部变量以及编译器自动生产的其他临时变量)
  • 保存上下文信息(包括在函数调用前后需要保持不变的寄存器)

2. 理解函数栈帧能解决什么问题呢?

理解函数栈帧有什么用呢?问题答案见文末,先不妨带着问题思考一下吧

只要理解了函数栈帧的创建和销毁,以下问题就能够很好的理解了:

  1. 局部变量是如何创建的?
  2. 为什么局部变量不初始化内容是随机的?
  3. 函数调用时参数时如何传递的?
  4. 传参的顺序是怎样的?
  5. 函数的形参和实参分别是怎样实例化的?
  6. 函数的返回值是如何带会的?

让我们一起走进函数栈帧的创建和销毁的过程中。  

3. 函数栈帧的创建和销毁解析

3.1 什么是栈?

栈(stack)是现代计算机程序里最为重要的概念之一,几乎每一个程序都使用了栈,没有栈就没有函 数,没有局部变量,也就没有我们如今看到的所有的计算机语言。

在经典的计算机科学中,栈被定义为一种特殊的容器,用户可以将数据压入栈中(入栈,push),也可 以将已经压入栈中的数据弹出(出栈,pop),但是栈这个容器必须遵守一条规则:先入栈的数据后出 栈(First In Last Out, FIFO)。就像叠成一叠的术,先叠上去的书在最下面,因此要最后才能取出。

在计算机系统中,栈则是一个具有以上属性的动态内存区域。程序可以将数据压入栈中,也可以将数据 从栈顶弹出。压栈操作使得栈增大,而弹出操作使得栈减小。 在经典的操作系统中,栈总是向下增长(由高地址向低地址)的。 在我们常见的i386或者x86-64下,栈顶由成为 esp 的寄存器进行定位的。

3.2 认识相关寄存器和汇编指令

相关寄存器

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

相关汇编命令

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

3.3 解析函数栈帧的创建和销毁

3.3.1 预备知识

首先我们达成一些预备知识才能有效的帮助我们理解,函数栈帧的创建和销毁

1. 每一次函数调用,都要为本次函数调用开辟空间,就是函数栈帧的空间。

2. 这块空间的维护是使用了2个寄存器: esp 和 ebp , ebp 记录的是栈底的地址, esp 记录的是栈顶 的地址

如图所示:

3.3.2 函数的调用堆栈

函数调用堆栈是反馈函数调用逻辑的,那我们可以清晰的观察到 ,main 函数调用之前,是由 invoke_main 函数来调用main函数。

那我们可以确定, invoke_main 函数应该会有自己的栈帧, main 函数和 Add 函数也会维护自己的栈 帧,每个函数栈帧都有自己的 ebp 和 esp 来维护栈帧空间。

那接下来我们从main函数的栈帧创建开始讲解:

3.3.4 准备环境

为了让我们研究函数栈帧的过程足够清晰,不要太多干扰,我们可以关闭下面的选项,让汇编代码中排 除一些编译器附加的代码

3.3.5 转到反汇编

调试到main函数开始执行的第一行,右击鼠标转到反汇编。得到的代码整理如下:

转化为伪代码和图片可以得到:

小知识:烫烫烫~

下面的程序输出“烫”这么一个奇怪的字,是因为main函数调用时,在栈区开辟的空间的其中每一 个字节都被初始化为0xCC,而arr数组是一个未初始化的数组,恰好在这块空间上创建的,0xCCCC(两 个连续排列的0xCC)的汉字编码就是“烫”,所以0xCCCC被当作文本就是“烫”。  

接下来我们再分析main函数中的核心代码:

上面已经告诉大家看反汇编的方法啦,代码太长就不放在文章里面了,大家可以自己实现,对照下面的图进行理解:

拓展了解:

其实返回对象时内置类型时,一般都是通过寄存器来带回返回值的,返回对象如果时较大的对象时,一 般会在主调函数的栈帧中开辟一块空间,然后把这块空间的地址,隐式传递给被调函数,在被调函数中 通过地址找到主调函数中预留的空间,将返回值直接保存到主调函数的。

具体可以参考《程序员的自我 修养》一书的第10章。   到这里已经给大家完整的演示了main函数栈帧的创建,Add函数站真的额创建和销毁的过程,相信大家 已经能够基本理解函数的调用过程,函数传参的方式,也能够回答文章开始处的问


Q&A

局部变量是如何创建的?

局部变量是在函数或代码块内部声明的变量。当程序执行到包含局部变量声明的函数或代码块时,该变量会被创建并分配内存空间。局部变量只在声明它的函数或代码块内部可见,超出其作用域范围后就会被销毁

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

栈上的数据并不会被自动初始化为特定的值。当程序执行到声明局部变量的语句时,编译器会为该变量分配一块内存空间,但并不会对其进行初始化操作。因此,该内存空间中原本存储的是之前使用过的数据,导致局部变量的内容是随机的。

函数调用时参数时如何传递的?

在传值调用中,实参的值被复制到形参中,函数内部对形参的修改不会影响实参的值。

传参的顺序是怎样的?

按照声明的顺序来确定的,,而不是按照实参在函数调用中的顺序。

函数的形参和实参分别是怎样实例化的?

形参的实例化:函数的形参是在函数定义或声明时指定的参数,用于接收函数调用时传递的实参的值

实参的实例化:实参是函数调用时传递给函数的值,它们可以是常量、变量或表达式。

函数的返回值是如何带会的?

在栈桢中,函数的返回值通常存储在栈的某个位置上,例如在栈桢的顶部或者是返回地址的下一个位置。当函数执行完毕后,程序会将该位置上的值取出,并传递给调用函数。由于该值存储在main栈桢中了,在函数调用结束后并不会立即被销毁,因此函数的返回值也就不会被销毁,可以被传递给调用函数。

tips: 如果函数声明的返回类型是void,则表示函数没有返回值,可以使用return语句来提前结束函数的执行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/9507.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI智能分析高精度烟火算法EasyCVR视频方案助力打造森林防火建设

一、背景 随着夏季的来临,高温、干燥的天气条件使得火灾隐患显著增加,特别是对于广袤的森林地区来说,一旦发生火灾,后果将不堪设想。在这样的背景下,视频汇聚系统EasyCVR视频融合云平台AI智能分析在森林防火中发挥着至…

广告归因数据回传:打造低成本、高ROI的oCPX模型

优化成本、提升转化,这一直是App效果广告买量投放的两大核心目标。广告归因中的数据回传正是因此而生,在投放oCPX类智能出价时,通过数据回传,数据算法不断对模型进行调优,广告投放机器人就会变得更加地聪明和智能&…

css 子元素 圆 均匀分布 展开动画

一般情况下使用scss就可以实现 import "math";#app {display: flex;align-items: center;justify-content: center;width: 200px;height: 200px;position: relative;border-radius: 50%;border: 1px solid #000;> span {position: absolute;display: flex;align-…

什么是HTTP/2?

HTTP/2(原名HTTP 2.0)即超文本传输协议第二版,使用于万维网。HTTP/2主要基于SPDY协议,通过对HTTP头字段进行数据压缩、对数据传输采用多路复用和增加服务端推送等举措,来减少网络延迟,提高客户端的页面加载…

Java数组(如果想知道Java中有关数组的知识点,那么只看这一篇就足够了!)

前言:数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同,Java 语言中提供的数组是用来存储固定大小的同类型元素。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSD…

PixelYourSite PRO插件下载:提升网站性能与用户体验的终极解决方案

在数字时代,网站的性能和用户体验是企业成功的关键。PixelYourSite PRO插件是专为WordPress网站设计的一款高效工具,旨在通过先进的像素管理和优化技术,提升网站加载速度,增强用户互动,从而显著提高转化率。 一、为什…

智慧便民小程序源码系统 求职招聘+房产出租+相亲交友 带完整的安装代码包以及系统搭建教程

在数字化、智能化的今天,我们的生活节奏越来越快,对于各种服务的需求也越发多元化和个性化。为了满足广大市民对于便捷、高效、全面的服务需求,罗峰给大家分享一款智慧便民小程序源码系统,集求职招聘、房产出租、相亲交友三大功能…

深入理解指针(4)

目录 1. 字符指针变量2. 数组指针变量2.1 数组指针变量是什么?2.2 数组指针变量怎么初始化 3. ⼆维数组传参的本质4. 函数指针变量4.1 函数指针变量的创建4.2 函数指针变量的使⽤4.3 两段有趣的代码4.3.1 typedef 关键字 5. 函数指针数组6. 转移表 1. 字符指针变量 …

处理解决python

1、问题现象: ModuleNotFoundError: No module named pkg_resources 2、解决方案 安装pip install setuptools即可解决:

Windows环境下VSCode C无法跳转自动补全

前言: 本文记录了自己在配置 Windows环境下 VSCode C开发环境的遇到的问题和解决方法。 参考: vscode c语言没有代码提示_clangd提示不生效-CSDN博客 VSCODE无法跳转_vscode 不能跳转-CSDN博客 vscode c/c环境配置(MinGW)调用第三官方库…

华为OD机试 - 反射计数 - 矩阵(Java 2024 C卷 200分)

华为OD机试 2024C卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷C卷)》。 刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试…

Vulstack红队评估(一)

文章目录 一、环境搭建1、网络拓扑2、web服务器(win7)配置3、域控(winserver2008)配置4、域内机器(windows 2003)配置5、调试网络是否通常 二、web渗透1、信息搜集2、端口扫描3、目录扫描4、弱口令5、phpmyadmin getshell日志gets…

OBS插件--声音波形显示

声音波形显示 波形显示是一个可以定制化的动态音频频谱图案,可以多音频进行可视化,对于音乐类主播必不可少,通过灵活的配置选项可以设计出非常个性化的频谱图形。 下面截图演示下操作步骤: 首先,打开 OBS直播助手 在…

探索生命奥秘的新征程:谷歌AlphaFold 3发布!

大家好!今天和大家分享的是让人热血沸腾的消息——谷歌AlphaFold 3的发布!这次的新版本可不仅仅是一次升级,而是一次生物科技的革命! 回顾一下AlphaFold系列的历程,从AlphaFold 1的问世到AlphaFold 2的惊艳登场&#…

ChatGPT Web Midjourney一键集成最新版

准备工具 服务器一台 推荐使用浪浪云服务器 稳定 安全 有保障 chatgpt api 推荐好用白嫖的api 项目演示 项目部署 浏览器访问casaos 添加软件原添加 https://gitee.com/langlangy_1/CasaOS-AppStore-LangLangy/raw/master/chatmjd.zip 安装此软件 等待安装 安装后再桌面设置…

信息安全技术-分析题【太原理工大学】

没有历年题或明确说明大题会考什么,以下为个人猜测 简答题和选择判断占60,认真看题库和总结,能过d(^_^o) 好像说是加解密这类题会给公式让你直接套,但还是看一下基本原理,要不到时候蒙圈 1.加密算法步骤 图 1 是一个采…

Spring Boot | Spring Boot 整合 “异步任务“ 的实现

目录: 一、异步任务1.1 "无返回值" 异步任务调用 :① 创建项目② 编写 "异步调用方法" ( 使用 Async 注解 )③ "主程序启动类"中 开启基于 "注解" 的异步任务支持 ( 使用EnableAsync注解 )④ 编写 "控制层" 相关…

从0到1构建AI agent【零代码】

一、前言 想象一下,如果AI的想象力被彻底释放,那将是一场怎样的革命?“大语言模型不过是个贪吃蛇,而AI Agent却能创造出‘王者荣耀’。”这不仅是网上的一句戏言,它预示着一个不可逆转的趋势。比尔盖茨更是一语中的&am…

【全开源】Java共享台信息共享系统源码

特色功能 信息整合与共享:该平台提供一站式信息整合服务,将各种类型的信息资源进行汇聚,方便用户快速查找和获取所需资源。多种共享功能:支持信息共享、共享车位、共享会议室、共享电动车等多种共享功能,提高资源利用…

【Linux】18. 进程间通信 --- System V IPC(选学)

System V IPC System V 消息队列System V 共享内存System V 信号量 system V 共享内存 共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核。 换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据…