C函数调用约定

Python基础知识学习05:函数再认识 1、知识回顾 局部变量与全局变量的介绍前文已作详细介绍,这里我们简单描述即可。 局部变量:定义在函数体内部的变量,它只在函数体内部生效。如果在函数外部访问则会立即报错。全局变量:指的是在函数体内、外都能生效的变量。如需在函数体内部修改全局变量,先global 关键字声明a是全局变量,再进行赋值即可。 2、多函数程序执行流程 2.1 共用全局变量 2.2 返回值作为参数 ... 阅读详情

C中采用了不同的调用方式来调用函数,这里的函数调用概念可能与我们通常所理解的函数调用有所不同,它们指的是处理器在处理函数上的差异。理解这些不同的方式有助于我们来调试程序和链接我们的代码。在此我想讨论一下主要的四种函数调用方法以及之间的区别,它们是__stdcall、__cdecl、__fastcall、thiscall。当然,还有一些更加不常用的函数调用方法比如naked call我也将顺便提及。

   
不同的函数调用方法之间的主要有以下一些区别:
① 当参数个数多于一个时,按照什么顺序把参数压入堆栈函数调用后
② 谁来恢复堆栈
③ 编译后的修饰名规则

__stdcall
:将参数压栈是按PASCAL语言的顺序(从右到左),通常用于WINAPI中。它是由被调用者将参数从栈中清除的,所以它的编译文件比__cdecl小。__stdcall是Windows API函数中默认的调用约定,被调函数自己在退出时清空堆栈。这种调用方式不能实现变参函数,因为被调函数不能事先知道弹栈数量,但在主调函数中是可以做到的,因为参数数量由主调函数确定。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。如函数int func(int a,  double b)的修饰名是_func@12。
编译选项/Gz。


注意:在创建DLL时,一般使用__stdcall调用(Win32 Api方式),采用__functionname@number命名规则,因而各种语言间的DLL能互相调用。也就是说,DLL的编制与具体的编程语言及编译器无关,只要遵守DLL的开发规范和编程策略,并安排正确的调用接口,不管用何种编程语言编制的DLL都具有通用性。


__cdecl
:是C语言采用的默认调用方法,参数按从右到左的顺序压入栈,由调用者把参数弹出栈,它的优点是支持printf这样的可变参数调用。一般可变参数函数的调用都采用这种方式,比如int __cdecl scanf (const char *format,…)。对于"C",修饰名是在函数名前加下划线,如函数void test(void)的修饰名是__test。除非声明为 extern "C",否则 C++ 函数将使用不同的名称修饰方案。
   
编译选项/Gd。

   
注意:CC++中的main(或wmain)函数的调用约定必须是__cdecl,不允许更改。


__fastcall
:__fastcall调用较快,它通过CPU内部寄存器传递参数。头两个DWORD类型或者占更少字节的参数被放入ECX和EDX寄存器,其他剩下的参数按从右到左的顺序压入栈。由被调用者把参数弹出栈,对于“C”函数或者变量,修饰名以“@”为前缀,然后是函数名,接着是符号“@”及参数的字节数,如函数int func(int  a, double b)的修饰名是@func@12。
编译选项/Gr,通常减少执行时间。


   
注意:在对用内联程序集语言编写的任意函数使用__fastcall 调用约定时,一定要小心。您对寄存器的使用可能与编译器对它们的使用发生冲突。Microsoft 不保证不同编译器版本之间的 __fastcall 调用约定的实现相同。例如,16 位编译器与 32 位编译器的实现就不同。因此当使用 __fastcall 命名约定时,请使用标准包含文件。否则将获取无法解析的外部引用。


   thiscall
: 函数体 this指针默认通过ECX传递,其它参数从右到左入栈。thiscall是唯一一个不能明确指明的函数修饰,因为thiscall不是关键字。它是C++类成员函数缺省的调用约定。由于成员函数调用还有一个this指针,因此必须特殊处理。
thiscall
意味着:参数从右向左入栈,如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压栈后被压入堆栈。对参数个数不定的,调用者清理堆栈,否则函数自己清理堆栈。

 


有人对用用的编译器的调用约定进行了小部分总结,share一下。

VC6:


        调用约定        堆栈清除    参数传递
        __cdecl                  调用者      从右到左,通过堆栈传递
        __stdcall                  函数体         从右到左,通过堆栈传递
        __fastcall                 函数体         从右到左,优先使用寄存器(ECX,EDX),然后使用堆栈
        thiscall                     函数体         this指针默认通过ECX传递,其他参数从右到左入栈


__cdecl是C\C++的默认调用约定; VC的调用约定中并没有thiscall这个关键字,他是类成员函数默认调用约定;
C\C++中的main(或wmain)函数的调用约定必须是__cdecl,不允许更改;
默认调用约定一般能够通过编译器配置进行更改,假如您的代码依赖于调用约定,请明确指出需要使用的调用约定;

C++Builder6:


        调用约定        堆栈清除    参数传递
        __fastcall                  函数体      从左到右,优先使用寄存器(EAX,EDX,ECX),然后使用堆栈 (兼容Delphi的register)
        (register和__fastcall等同)
        __pascal                     函数体      从左到右,通过堆栈传递
        __cdecl                    调用者    从右到左,通过堆栈传递(和C\C++默认调用约定兼容)
        __stdcall                     函数体      从右到左,通过堆栈传递(和VC中的__stdcall兼容)
        __msfastcall                函数体      从右到左,优先使用寄存器(ECX,EDX),然后使用堆栈(兼容VC的__fastcall)

 


 

总结:调用约定是由函数类型来决定的,而又是和编译器相关的。代码不具备移植性。但是,函数参数入栈顺序一般都是从右到左的,这个要mark一下。

 

来一段程序显示一下函数参数的地址和调用参数的地址:

 

执行结果:

i=0:[8049768]
i=2:[bfffe630]
j=1:[bfffe634]
k=0:[bfffe638]
___________
l:bfffe624
g:bfffe620
function f() end___________

 

j=0:[bfffe654]
i=2:[bfffe630]
j=1:[bfffe634]
k=0:[bfffe638]
___________
l:bfffe624
g:bfffe620
function f() end___________

C语言函数调用约定及其实现细节 在C语言中,函数调用约定是指编译器和操作系统如何协调函数的调用和返回过程。函数调用约定定义了函数参数的传递方式、栈的使用规则以及寄存器的保存和恢复规则等细节,确保函数能够正确地接收参数并返回结果。本文将详细介绍几种常见的C语言函数调用约定,并提供相应的源代码示例。在本文中,我们介绍了几种常见的C语言函数调用约定,并提供了相应的代码示例。了解函数调用约定对于理解函数参数传递、栈的使用和寄存器的保存等方面的细节非常重要。通过正确理解和使用函数调用约定,我们可以编写出高效、可靠的C语言程序。 阅读详情

相关推荐

Verilog单周期CPU设计(超详细)

实验 单周期CPU一、设计目的与目标实验内容实验要求二、课程设计器材硬件平台软件平台三、 CPU逻辑设计总体方案指令模块MIPS指令格式指令处理流程数据通路总体结构图设计流程逻辑图四、模块详细设计PCAdd4PCINSTMEMDATAMEMSHIFTER32_L2SHIFTER_COMBINATIONMUX4X32MUX2X5EXT16T32MUX2X32CONUNITREGFILEALUSing...

Ace Cheney的博客 9万+

C++中_tmain与main,winMain,wmain区别与联系

用过C的人都知道每一个C的程序都会有一个main(),但有时看别人写的程序发现主函数不是int main(),而是int_tmain(),而且头文件也不是<iostream.h>而是<stdafx.h>,会困惑吧? 一起来看看他们有什么关系吧 首先,这个_tmain()是为了支持unicode所使用的main一个别名而已,既然是别名,应该有宏定义过的,在哪里定义的呢?就在...

xuxinrk的博客 2264

YOLOv8的Anchor-Free革新:从中心点预测到动态IoU匹配的全面解析

本文深入解析了YOLOv8采用Anchor-Free(无锚框)设计的核心优势与实现机制。通过摒弃预设锚框,模型直接预测目标中心点与宽高,结合解耦头、动态IoU匹配及Varifocal Loss等创新,显著简化了训练流程并提升了检测精度,尤其在小目标检测和模型泛化能力上表现突出。

weixin_29094301的博客 356

【逆向基础】五、函数调用约定(__cdecl,__stdcall,__fastcall,__thiscall)详解

逆向分析汇编伪代码时,我们常会遇到函数调用约定的修饰符;本文从函数的定义入手,从汇编角度详细解析了函数调用的过程;最后引入函数调用约定,让读者可以更快了解函数调用约定的相关内容

幸福之家的博客 2946

FPGA实战:手把手教你用Verilog驱动4.3寸RGB触摸屏(附完整代码)

本文详细介绍了如何使用Verilog语言在FPGA上驱动4.3寸RGB触摸屏,包括时序设计、信号交互原理及完整代码实现。通过双计数器引擎设计和参数化模块,开发者可以高效构建800*480分辨率的显示驱动,并解决工程实践中的信号完整性和时序收敛问题。

rice5的博客 701

Excel地理探测器实战:5分钟搞定空间分异性分析(附完整数据集)

本文详细介绍了如何使用Excel地理探测器插件进行空间分异性分析。通过5分钟实战教程,手把手指导数据格式准备、软件操作及四大探测器(分异及因子、交互作用、风险区、生态探测器)的结果解读,帮助规划师、研究者快速验证地理因素对现象分布的影响,大幅降低GIS分析门槛。

peace的博客 607

嵌入式软件工程师面经C/C++篇—函数调用约定:一文看懂 __cdecl 和 __stdcall(超详细入门)

本文详细解析C/C++中的两种函数调用约定:__cdecl和__stdcall。__cdecl是C语言默认约定,参数从右到左压栈,调用者负责清理栈,支持可变参数函数;__stdcall常用于Windows API,同样从右到左压栈,但由被调用者清理栈,效率更高但不支持可变参数。文章通过代码示例和汇编解析直观展示两种约定的区别,并指出在实际开发中调用约定不匹配可能导致链接错误或程序崩溃,强调确保函数声明与实际约定一致的重要性。理解这些规则对调用系统API和第三方库至关重要。

qq_59174845的博客 1162

vasp算表面吸附流程_VASP表面吸附计算实例分析

本文主要为了记录在学习Vasp计算过程中如何设置INCAR中的一些参数,并不着重讲解其含义,详见可自行到vasp官网查阅。其次关于建模部分也不做细致讨论,一般结构可从Materials Studio里自带的晶体数据库导出,或从三大数据库网站上下载:1、Materaials Project网址:https://materialsproject.org/(强烈推荐,邮箱注册即可使用)2、CCDC网址:...

weixin_39617669的博客 2240

C函数调用约定和返回值

文章目录一、函数调用约定1. 影响函数生成的符号名2. 影响形参内存的释放者_stdcall_fastcall_thiscall二、函数的返回值1. 0 < 返回值 <= 4字节3. 4字节 < 返回值 <= 8字节3. 返回值 > 8字节 一、函数调用约定 _cdecl:C调用约定 _stdcall:Windows标准的调用约定 _fastcall:快速调用约定 _thiscall:C++的成员函数调用约定 以上的函数调用约定入参都是从右向左,只有PASCAL从左向右 函数调

长期更新自学笔记 2022

【信息系统项目管理师】高分论文:论信息系统项目的整合管理(绩效考核系统)

我们将项目管理计划中的子计划包括项目范围、进度、成本、质量管理计划,过程改进计划,人力资源管理计划,风险、采购管理计划,干系人管理计划,项目范围、成本、进度基准作为依据,查看项目的各个方面,通过组织全体团体成员会议来解读由各监控过程提供的信息,之后我与项目管理团队一起制订所需措施,确保项目绩效达到预期要求。在一个项目中,变更是必然的,也是不可避免的,进度拖延,成本失控,客户有新的需求等都会引起项目的变更。在本项目中,我要求有处于工作状态的产品,开发人员才可以对其任意修改,修改完成后,重新入库即可。

数据知道的博客 6887

损失函数大汇总(三十八)(AUCPR Loss附公式推导与代码)

本文系统介绍了AUCPR Loss的原理与应用。针对不平衡分类任务中AUC指标不够敏感的问题,提出通过优化PR曲线面积(AUCPR)来提升模型性能。文章详细推导了AUCPR的可微近似实现:首先用sigmoid函数软化阈值判断,构造可微的TP/FP/FN计数;然后基于软Precision和Recall计算近似PR曲线面积;最后通过数值积分得到可优化的损失函数。特别讨论了温度参数τ对训练稳定性的影响,并比较了AUCPR与AUC、AP等指标的异同。该方法适用于医学筛查、欺诈检测等极端不平衡场景,能更准确反映模型对

悦学共鸣,温柔以待,汇聚光芒,共同成长 441

c语言之函数调用约定

在C和C++编程中,函数调用约定(Calling Convention)定义了函数参数如何传递、由谁负责清理栈(如果有的话)、以及返回值如何传递等规则。不同的平台和编译器可能采用不同的调用约定。不同的调用约定适用于不同的场景和需求。了解这些调用约定的特点和适用场景有助于编写更高效、更可移植的代码。在选择调用约定时,需要考虑目标平台、编译器、以及与其他代码或库的兼容性。

qq_45583706的博客 947

使用VNA(Vector Network Analyzer)对S参数进行去嵌(二)

无论是使用 EM 仿真工具创建的简化模型(如一段理想传输线)还是复杂模型用于测试夹具,现在都需要使用该 S 参数模型执行去嵌入过程。

小孟同学的博客 6108

c语言函数调用约定,函数调用约定

函数调用约定常见的函数调用约定[5]:cdecl,stdcall,fastcall,thiscall,naked callMFC调用约定(VS6:Project Settings->C/C++ Calling convention:)1. __cdecl(C调用约定.The C default calling convention)C/C++ 缺省调用方式a.压栈顺序:函数参数从右到左.b...

weixin_39630410的博客 909

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

C语言函数调用约定

 在C语言中,假设我们有这样的一个函数:int function(int a,int b)调用时只要用result = function(1,2)这样的方式就可以使用这个函数。但是,当高级语言被编译成计算机可以识别的机器码时,有一个问题就凸现出来:在CPU中,计算机没有办法知道一个函数调用需要多少个、什么样的参数,也没有硬件可以保存这些参数。也就是说,计算机不知道怎么给这个函数传递

Make Progress Everyday! 701

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

C/C++函数调用约定

C/C++函数调用约定 关于 C/C++ 函数调用约定,大多数时候并不会影响程序逻辑,但遇到跨语言编程时,了解一下还是有好处的。 VC 中默认调用是 __cdecl 方式,Windows API 使用 __stdcall 调用方式,在 DLL 导出函数中,为了跟 Windows API 保持一致,建议使用 __stdcall 方式。 调用约定跟堆栈清除密切相关。如果写一个汇编函数,给 C/C

wangwang4whu 634

C++:C/C++函数调用约定

C/C++调用约定 函数调用方式

Sauron7i的博客 1307

C与C++的函数调用约定

在C语言中,假设我们有这样的一个函数:int function(int a,int b)调用时只要用result = function(1,2)这样的方式就可以使用这个函数。但是,当高级语言被编译成计算机可以识别的机器码时,有一个问题就凸现出来:在CPU中,计算机没有办法知道一个函数调用需要多少个、什么样的参数,也没有硬件可以保存这些参数。也就是说,计算机不知道怎么给这个函数传递参数,传递

冷剑魂的专栏——垃圾场 1542

[VC]函数调用约定解析(C/C++)

C/C++函数调用约定和函数名称修饰规则探讨作者:星轨(oRbIt) 使用C/C++语言开发软件的程序员经常碰到这样的问题:有时候是程序编译没有问题,但是链接的时候总是报告函数不存在(经典的LNK2001错误),有时候是程序编译和链接都没有错误,但是只要调用库中的函数就会出现堆栈异常。这些现象通常是出现在C和C++的代码混合使用的情况下或在C++程序中使用第三方的库的情况下

solarwindsj的专栏 590

从汇编角度查看C语言函数调用约定

为了防止出现不必要的代码影响汇编语言的查看,所以程序中不使用任何库函数,以保持汇编代码的简洁。这里所使用的汇编是VC的MASM。默认函数调用方式__cdeclint add(int a, int b) { return a + b; }int main() { int a = 1, b = 2; return add(a,b); }对应汇编代码:; Listing gener

优快云文章已停止维护,后续文章会在 https://blog.hufeifei.cn 持续更新 2818
上一篇: 函数入参的压栈和求值
下一篇: "delete this;" in the member function
wunderup
博客等级 码龄20年 13粉丝 79原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值