函数的工作原理

递归函数工作原理 递归是一种较为特殊的算法,简单来说,“函数”(或者说子程序)不只是能够被其他函数调用(或者引用)的程序单元,在某些语言中函数提供了调用自己的功能,这种功能就是所谓的“递归”。递归的定义假如一个函数或者子程序是由自身所定义和调用的,就称为递归。递归至少要定义两种条件:一个是可以反复执行的递归过程,另一个是跳出执行过程的出口。递归的分类根据递归调用对象的不同,可以把递归分为以下两种: 1)直接递归:在 阅读详情

函数调用的工作流程  

  1. 传递参数:通过栈(_cdecl,_stdcall)或寄存器(_fastcall)。
  2. 函数调用:使用call指令调用函数,并将返回地址压入栈中。
  3. 保存栈底:将调用方的栈底寄存器ebp压栈。
  4. 申请栈空间,并保存寄存器环境:根据局部变量的多少提升esp(add esp,n)来开辟栈空间,用于存放函数的局部变量(VC6.0中debug模式这部分空间初始化为0XCC),并将函数中要用到的寄存器压栈进行保护。
  5. 函数实现代码
  6. 恢复寄存器环境:还原栈中保存的寄存器信息
  7. 平衡栈空间:平衡局部变量使用的栈空间,即进行降低esp操作(sub esp,n)。
  8. 函数返回:从栈顶取出第二步保存的返回地址
    • _cdecl调用方式,执行ret;相当于pop eip;(调用方平衡参数占用的栈空间)
    • 非_cdecl调用方式,执行ret n;相当于pop eip; add esp, n;(add esp,n 用于平衡参数占用的栈空间)

栈的形成和关闭

栈是内存中一段特殊的内存空间,后进先出原则。使用push、pop指令进行入栈、出栈操作。esp为栈顶寄存器,ebp为栈底寄存器,栈是向下生长的,即往地址低处生长。若栈非空,则esp指示的地址比ebp指示的地址小;若esp指示地址比ebp指示地址大,则为空栈。在VC6.0中,栈中可寻址的数据有局部变量、函数返回地址、函数参数等。当进行函数调用时,系统会开辟此函数所需的栈空间,而函数调用结束时,将释放开辟的栈空间,这一过程称为栈平衡。

函数调用方式说明

  1. _cdecl: C/C++默认的调用方式,调用方平衡函数参数所使用的栈空间。在函数返回后执行add esp, x(其中x为所有参数所占用栈空间大小,以字节为单位)
  2. _stdcall:被调方平衡函数参数所使用的栈空间,即在函数返回时使用ret n指令。不定参数的函数无法使用此种调用方式。
  3. _fastcall: 使用寄存器传递参数,只使用了ecx和edx,分别传递第一个和第二个参数(从左往右分别为第一个、第二个...),其他参数则用栈传递。此种方式调用效率最高。
  • _cdecl和_stdcall对比(VC6.0 Debug模式下)注意:在Release模式下_cdecl参数平衡时可能存在复写传播优化)
图(1)源码:_cdecl与_stdcall的对比——Debug模式
图(2) 上图源代码的反汇编代码
  • _fastcall调用方式(VC6.0 Debug模式下)
图(3) 源码 _fastcall示例
图(4)上图源代码的反汇编代码
如上所示,最后的ret 8语句便是被调用平衡参数所占用的栈空间。而在调用方call @ILT+15(ShowFast)(00401014)后不用平衡参数所用栈空间。

函数参数

    函数参数通过栈结构或寄存器进行传递,在C++代码中,传参顺序是自右向左依次入栈。参数也是函数中的变量。但与函数中局部变量的存放地址有些许不同。相对esp来说,局部变量存放地址偏移量为负数,而参数存放地址偏移量为正数。
    采用非引用形参,则push指令将形参复制到栈顶(即为实参的副本),与实参数据在两个不同的地址处,是独立存在的,因此对函数参数的修改,实际上是对当前保存在栈内参数中保存的值进行修改,与实参数据没有关系。所以说,在C/C++中,形参是实参的副本,对形参的修改不影响其实参。


函数返回值

    调用函数时,先将参数入栈,再执行call指令后,将返回地址压入栈中,调用完毕后执行ret指令,弹出返回地址到eip,并进行参数所用栈平衡操作。在VC中使用寄存器eax来保存返回值,若返回值大小打于4字节,则使用eax和edx来保存返回值。

你的小程序地图功能还只是“摆设”吗?支付宝地图API的深度玩法都在这里了! 🏆本文收录于《滚雪球学支付宝小程序开发》专栏,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!! 阅读详情

相关推荐

AUTOSAR入门

一、AUTOSAR是什么 AUTOSAR组织自己的介绍是 AUTOSAR (AUTomotive Open System ARchitecture) is a worldwide development partnership of vehicle manufacturers, suppliers, service providers and companies from the automot...

天涯遍地是小草的博客 3万+

函数工作原理

*函数由多个部分组成:*1.函数名 函数名是函数开始地址的一个标签2.参数 函数的参数是给函数处理的资料,是函数中的变量。比如,在数学中,有个sine函数。如果你想让计算机计算2的正弦值,那么你可以调用函数名为sine的函数,以2为参数。另外,函数的参数可以有不止一个,甚至可以没有3.本地变量4.静态变量 静态变量是直到程序结束都一直有效的变量。函数内的静态变量对其他模

Dreamer的博客 1647

三代测序选型指南:PacBio HiFi vs Nanopore vs Illumina技术对比与适用场景

本文深入对比了三代测序技术PacBio HiFi、Nanopore与Illumina的核心参数、成本模型和应用场景,为生物信息学研究提供选型指南。通过实测数据和技术组合策略分析,帮助实验室根据研究需求选择最适合的测序方案,涵盖基因组组装、表观遗传学等关键应用领域。

fern8的博客 904

C++之类的成员函数的原理

先来一个类的成员函数的例子:#include<iostream>using namespace std;class MyTime { private: int hour; int minute; int second; public: void settime(int h, int m, int s) { hour = h; minut

maoliran的博客 1792

41-dify案例分享-基于database插件实现Text2sql的数据库查询图表工作流

本文介绍基于 Text2SQL 的 Dify 工作流实现过程。先阐述 Text2SQL 概念、步骤及应用领域。接着说明工作流制作,包括用 chatflow 加开场白、获取系统时间,配置 LLM 生成 SQL,用 SQL Execute 工具查询,经 LLM 汇总结果,代码生成 ECharts 数据,条件分支判断图表类型输出。最后介绍验证测试、提供体验地址,还提及借助工具生成建表和初始化数据 SQL 语句。

个人技术 1万+

Matlab TreeBagger实战:用随机森林预测房价的5个关键步骤(附完整代码)

本文详细介绍了使用Matlab的TreeBagger工具包构建随机森林模型预测房价的完整流程。通过波士顿房价数据集实战,涵盖数据预处理、模型构建、参数调优、特征重要性分析及高级应用(如分位数回归)等5个关键步骤,并附有完整代码,帮助读者快速掌握这一强大的回归分析工具。

ol789012的博客 444

2021-04-23

第四天: 成员函数和普通函数的区别: 成员函数是面向对象的概念,所谓的成员函数,是指一个函数作为类的成员,公有成员、私有成员或者保护成员。 普通函数一般有两种传递方式,按类型传递和按值传递,也就是传指针和传返回值两种情况。成员函数一般是按类型传递,也即是传指针地址。 普通函数可以随便调用,并且无法继承和封装,成员函数根据类的不同,可以进行继承,根据公有私有的不同,调用方式也不同。 深层次的区别,普通函数作为C语言的概念,用的是stdlib,成员函数是用iostream,编译方法不同,至于谁占内存多,并不好

meng_1413的博客 346

植物GO注释

本文主要是对没有GO term库的植物进行注释。 1、选用AgriGo 进行注释,在agriGO中点击species后,查看与你目标物种相近的物种作为库 2、比如我以甜菜为例 为了找到和GO term对应的ID,先找到PLAZA,进入网站https://bioinformatics.psb.ugent.be/plaza/versions/plaza_v3_di...

weixin_30300225的博客 2226

C/C++中的函数参数传递机制

 一、 函数参数传递机制的基本理论   函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题。基本的参数传递机制有两种:值传递和引用传递。以下讨论称调用其他函数的函数为主调函数,被调用的函数为被调函数。   值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放

weiqiao00的专栏 525

2026开源API网关横评:微服务与AI流量治理如何选型

API网关作为微服务架构的流量入口,承担着路由转发、安全管控、限流熔断等核心职责,是分布式系统治理的基础设施。随着大模型应用的普及,AI流量对网关提出了新的要求,如流式响应支持、Token级限流、多模型路由和成本分账等能力。传统网关通过插件拼凑AI功能,而AI原生网关则将这些能力内建。面对众多开源方案,如何根据业务场景做出合理选型?本文对Kong、APISIX、Higress、Envoy Gateway、MAI Gateway等主流开源API网关进行横向评测,从性能、动态性、K8s集成度、AI流量治理等维度

weixin_34242819的博客 482

华为OD机试双机位C卷-敌情监控 (Py/Java/C/C++/Js/Go)

华为OD机试(机考)双机位C卷 【敌情监控】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试 - 敌情监控。

qq_45776114的博客 938

析构函数的工作原理

如果对象是new出来的,那么它就是一个堆对象,不会被操作系统自动回收,需要我们手动调用delete函数释放该堆对象,在delete函数中会先调用析构函数释放该对象所申请的资源,那么析构函数如何释放对象所申请的资源呢,就是前面所说的,析构函数又会调用delete函数来释放对象所申请的资源,当然如果对象没有申请资源,那么就无需调用delete函数。

weixin_44049823的博客 2126

LLaMA-Factory微调教程5:多模态VLM模型对话

视觉-语言模型(VLM)概述与应用 视觉-语言模型(VLM)是一类结合视觉和语言信息的人工智能模型,旨在实现跨模态的理解与交互。其核心目标包括跨模态理解和生成能力,关键技术涉及模态表示与映射、多模态预训练以及跨模态交互机制。 典型VLM模型包括: CLIP:通过对比学习实现图像和文本的向量空间对齐 BLIP:结合自监督和弱监督学习提升语义对齐 ALBEF:基于BERT结构扩展跨模态注意力 DALL-E系列:基于文本生成图像的生成式模型 CLIP4Clip:扩展CLIP到视频领域 VLM在图像/视频检索、视觉

Cachel Wood的博客 1114

变量和函数底层工作原理

变量和函数的底层工作原理涉及内存管理和指令执行。变量在编译期通过符号表记录类型和偏移量,运行时根据作用域分配到数据段、栈或堆中,通过地址计算访问。函数调用通过栈帧管理参数、返回地址和局部变量,执行call指令跳转至代码段,完成操作后通过ret返回。关键机制包括内存分段(代码段、数据段、栈、堆)和栈帧结构(由ebp和esp界定),实现程序的高效执行和内存访问。

Dd000110的博客 1096

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

C++中虚函数的作用和虚函数的工作原理

https://www.cnblogs.com/zkfopen/p/11061414.html

heart18335101121的博客 295

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C语言基础 -- scanf函数的工作原理

在C语言中,输入主要是靠标准输入函数,也就是scanf函数来完成的。要正确的调用scanf函数来完成输入,需要了解scanf的工作原理。为了讲清楚原理,我先铺垫一下,介绍几个概念。(1)输入流:就是输入缓存区中从输入设备中输入的一系列字符。在我们个人电脑上,输入设备就是键盘,你从键盘上敲的一堆东西就是输入流。在PTA等刷题网站,实际上使用文件模拟了输入流,题目中的输入样例,还有测试点中的输入也是输入流。(2)匹配字符串:匹配字符串就是scanf函数调用时传入的第一个参数。也就是双引号里的那些字符。

LCCprogrammer 2476

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Django视图函数的工作原理

Django视图函数的工作原理,HTML表单的一些基础机制,POST请求与GET请求的对比

2401_84561760的博客 470

C++虚函数的工作原理

静态绑定与动态绑定 讨论静态绑定与动态绑定,首先需要理解的是绑定,何为绑定?函数调用与函数本身的关联,以及成员访问与变量内存地址间的关系,称为绑定。 理解了绑定后再理解静态与动态。 静态绑定:指在程序编译过程中,把函数调用与响应调用所需的代码结合的过程,称为静态绑定。发生在编译期。 动态绑定:指在执行期间判断所引用对象的实际类型,根据实际的类型调用其相应的方法。程序运行过程中,把函数调...

weixin_30670925的博客 131

虚函数的工作原理

虚函数的工作原理:       编译器处理虚函数的方法:给每一个对象添加一个隐含的成员。隐含成员中保存了一个指向函数地址数组的指针。这个数组叫做 虚函数表(virtual function table) 1.假如一个类中有虚函数的话,对象的起始位就是虚函数表指针。虚表指针 2.基类   虚函数表中 存有所有虚函数的地址 3.派生类 包含有独立的虚函数表 (多继承有多个虚函数表,

精彩的艺术 549

C++ 虚函数与虚函数的工作原理

文章目录虚函数虚析构函数虚函数的工作原理获取对象的虚函数表地址 虚函数 给类函数声明virtual关键字,将该函数解释为虚函数。基类定义的虚函数表明子类可以继承并实现该虚函数。虚函数的最大作用为:可以通过基类指针或引用来接收一个子类指针或者引用,并通过基类指针或引用来调用虚函数来实现相同的动作不同的实现方式,达到多态的目的。 例子代码如下: #include <iostream> #include <string> using namespace std; class BaseC

白杨 920

函数调用 压栈的工作原理

   1.开篇   本篇文章着重写的是系统中栈的工作原理,以及函数调用过程中栈帧的产生与释放的过程,有可能名字过大,如果不合适我可以换一个名字,希望大家能够指正,小丁虚心求教!如果有哪里写的不清楚的或者错误的地方请及时更正,小丁再次谢过了。文章里面有错别字,也可能会有好友说寄存器的32、16位的区别其实我感觉这里主要讲的还是些原理性的东西,后续会将文章图片错别字进行调

u011555996的博客 2万+

构造函数的工作原理

构造函数的工作原理 首先,编写一个Duck类的构造函数。 function Duck(type,canFly){ this.type=type; this.canFly=canFly;g } 然后,用new关键字创建一个新的Duck对象 var fido=new Duck("white duck",false); 接下来详细说明一下构造函数的工作原理 new 首先创建了一个...

qq_43062639的博客 1294

笔试面试题3——虚函数的工作原理

3.虚函数的工作原理 详见::http://blog.youkuaiyun.com/hackbuteer1/article/details/7883531

WQP_Ya_Ping的博客 541
上一篇: 数据结构 绪论
下一篇: 结构体和类
Yangping_Peng
博客等级 码龄14年 0粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值