C/C++函数调用的几种方式总结
调用函数时,计算机常用栈来存储传递给函数的参数。
栈是一种先进后出的数据结构,栈有一个存储区、一个栈顶指针。栈顶指针指向堆栈中第一个可用的数据项(被称为栈顶)。用户可以在栈顶上方向栈中加入数据,这个操作被称为压栈(Push),压栈以后,栈顶自动变成新加入数据项的位置,栈顶指针也随之修改。用户也可以从堆栈中取走栈顶,称为弹出栈(pop),弹出栈后,栈顶下的一个元素变成栈顶,栈顶指针随之修改。函数调用时,调用者依次把参数压栈,然后调用函数,函数被调用以后,在堆栈中取得数据,并进行计算。函数计算结束以后,或者调用者、或者函数本身修改堆栈,使堆栈恢复原装。
在参数传递中,有两个重要的问题必须要明确说明:
1. 当参数个数多于一个时,按照什么顺序把参数压入堆栈;
2. 函数调用后,由谁来把堆栈恢复原状。
在高级语言中,就是通过函数的调用方式来说明这两个问题的。常见的调用方式有:
stdcall
cdecl
fastcall
thiscall
thiscall
naked call
下面就分别介绍这几种调用方式:
1. stdcall
stdcall调用方式又被称为Pascal调用方式。在Microsoft C++系列的C/C++编译器中,使用PASCAL宏,WINAPI宏和CALLBACK宏来指定函数的调用方式为stdcall。
stdcall调用方式的函数声明为:
int _stdcall function(int a, int b);
stdcall的调用方式意味着:
(1) 参数从右向左一次压入堆栈
(2) 由被调用函数自己来恢复堆栈
(3) 函数名自动加前导下划线,后面紧跟着一个@,其后紧跟着参数的尺寸
上面那个函数翻译成汇编语言将变成:
push b 先压入第二个参数
push a 再压入第一个参数
call function 调用函数
在编译时,此函数的名字被翻译为_function@8
2. cdecl
cdecl调用方式又称为C调用方式,是C语言缺省的调用方式,它的语法为:
int function(int a, int b) // 不加修饰符就是C调用方式
int _cdecl function(int a, int b) // 明确指定用C调用方式
cdecl的调用方式决定了:
(1) 参数从右向左依次压入堆栈
(2) 由调用者恢复堆栈
(3) 函数名自动加前导下划线
由于是由调用者来恢复堆栈,因此C调用方式允许函数的参数个数是不固定的,这是C语言的一大特色。
此方式的函数被翻译为:
push b // 先压入第二个参数
push a // 在压入第一个参数
call funtion // 调用函数
add esp, 8 // 清理堆栈
在编译时,此方式的函数被翻译成:_function
3. fastcall
fastcall 按照名字上理解就可以知道,它是一种快速调用方式。此方式的函数的第一个和第二个DWORD参数通过ecx和edx传递,
后面的参数从右向左的顺序压入栈。
被调用函数清理堆栈。
函数名修个规则同stdcall
其声明语法为:
int fastcall function(int a, int b);
4. thiscall
thiscall 调用方式是唯一一种不能显示指定的修饰符。它是c++类成员函数缺省的调用方式。由于成员函数调用还有一个this指针,因此必须用这种特殊的调用方式。
thiscall调用方式意味着:
参数从右向左压入栈。
如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压入栈后被压入栈。
参数个数不定的,由调用者清理堆栈,否则由函数自己清理堆栈。
可以看到,对于参数个数固定的情况,它类似于stdcall,不定时则类似于cdecl。
5. naked call
是一种比较少见的调用方式,一般高级程序设计语言中不常见。
函数的声明调用方式和实际调用方式必须一致,必然编译器会产生混乱。
函数名字修改规则:
1. C编译时函数名修饰约定规则:
__stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数,格式为_function@8。
__cdecl调用约定仅在输出函数名前加上一个下划线前缀,格式为_function。
__fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,格式为@function@8。
它们均不改变输出函数名中的字符大小写,这和PASCAL调用约定不同,PASCAL约定输出的函数名无任何修饰且全部大写。
2. C++编译时函数名修饰约定规则:
__stdcall调用约定:
(1)以“?”标识函数名的开始,后跟函数名;
(2)函数名后面以“@@YG”标识参数表的开始,后跟参数表;
(3)参数表以代号表示:
X--void ,
D--char,
E--unsigned char,
F--short,
H--int,
I--unsigned int,
J--long,
K--unsigned long,
M--float,
N--double,
_N--bool,
....
PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以“0”代替,一个“0”代
表一次重复;
(4)参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;
(5)参数表后以“@Z”标识整个名字的结束,如果该函数无参数,则以“Z”标识结束。
其格式为“?functionname@@YG*****@Z”或“?functionname@@YG*XZ”,例如
int Test1(char *var1,unsigned long)-----“?Test1@@YGHPADK@Z”
void Test2() -----“?Test2@@YGXXZ”
__cdecl调用约定:
规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的“@@YG”变为“@@YA”。
__fastcall调用约定:
规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的“@@YG”变为“@@YI”。
VC++对函数的省缺声明是"__cedcl",将只能被C/C++调用。
C/C++函数调用的几种方式总结相关推荐
- python函数调用的三种方式_python函数调用的四种方式
原标题:python函数调用的四种方式 第一种:参数按顺序从第一个参数往后排#标准调用 运行结果: 第二种:#关键字调用 注意:关键调用从哪开始的,从哪以后都必须使用关键字调用除了'*'收集参数.不能 ...
- C/C++函数调用的几种方式
2019独角兽企业重金招聘Python工程师标准>>> 我们知道,调用函数时,计算机常用栈来存放函数执行需要的参数,由于栈的空间大小是有限的,在windows下栈是向低地址扩展的数据 ...
- python函数调用的三种方式_判断python对象是否可调用的三种方式及其区别
基本上判断python对象是否为可调用的函数,有三种方法: 1.使用内置的callable函数 callable(func) 用于检查对象是否可调用,返回True也可能调用失败,但是返回False一定 ...
- html里定义函数调用函数调用,函数调用的三种方式是什么?
函数的三种调用方式 第一种: 函数立即调用执行模式.这里面的this指向window;function add(a,b){ console.log(this); return a+b; } add() ...
- javascript函数调用的几种方式
function fn() {console.log(this.name);return "fn函数的返回值";}/*1.方法调用*///方法调用,this指向window,相当 ...
- php调用方式,php 函数调用的几种方式
// 最常见的函数调用 --- 1 function userFunction1($param1, $param2){ echo 'UserFunction1: Param1 : ',$param1, ...
- Python实现多进程的4种方式
Python多进程 - 实现多进程的几种方式 原文:http://blog.csdn.net/topleeyap https://blog.csdn.net/topleeyap/article/det ...
- java clone方法_干货满满:Java中创建对象的五种方式详解
通常来说,对象具有状态和行为,变量用来表明对象的状态,方法表明对象所具有的行为. 作为Java开发者,我们通常都是使用依赖管理系统,比如Spring去创建Java对象,但使用管理系统创建对象并不是唯一 ...
- Java中创建对象的5种方式 -[转] http://www.codeceo.com/article/5-ways-java-create-object.html...
作为Java开发者,我们每天创建很多对象,但我们通常使用依赖管理系统,比如Spring去创建对象.然而这里有很多创建对象的方法,我们会在这篇文章中学到. Java中有5种创建对象的方式,下面给出它们的 ...
最新文章
- ParLECH: Parallel Long-Read Error Correction with Hadoop
- 设计模式--建造者(Builder)模式
- LinkedList详解,看这篇就够了
- 查看移动平均价的历史记录
- java servlet .net_JAVA学习之 Model2中的Servlet与.NET一般处理程序傻傻分不清楚
- 数组排序并找出元素索引--Where do I belong-FCC
- 现实问题从数学化到离散化再到程序化
- 关于Tokenizer与TokenFilter的区别
- win7修改hosts文件方法
- 简述c、c++和java三大语言特性
- JAR文件概述(2021版)
- 【黑苹果教程】说点闲话
- python ffmpeg解码视频_利用python+ffmpeg合并B站视频及格式转换的实例代码
- 360 error.html,360浏览器出错了怎么办
- 美国小学计算机编程课程,美国小学STEM课程案例研究
- android手机fingerprint,Fingerprint HIDL
- LC振荡电路的工作原理
- 人工智能—— 产生式表示法
- JAVA-实现接入企业微信发送消息(最详细代码讲解!)
- 边云协同的优点_探析云边协同的九大应用场景
热门文章
- linux命令看文件内容,Linux文件内容查看相关命令
- php网页 安装插件,插件安装流程
- c语言在一个文件后面添加数据类型,c语言简单入门之简单运行和数据类型
- win10安装程序无法将配置为在此计算机,win10安装程序无法正常启动(完美解决)
- python音频转文字speech recognition_使用SpeechRecognition进行语音识别
- 堆叠柱形图上自定义数字_用Excel绘制Cell上的漂亮配图
- 会飞的汽车来了!旋翼式陆空两栖智能飞车研发成功
- 通电就可以工作,这些单片机真香!
- 关于硕士研究生的几点思考
- 单片微型计算机 第九章自测题,单片微型计算机网上练习题答案..doc