C 语言有 __cdecl、__stdcall、__fastcall、naked、__pascal。

C++ 语言有 __cdecl、__stdcall、__fastcall、naked、__pascal、__thiscall,比 C 语言多出一种 __thiscall 调用方式。

下面详细介绍如上六种调用方式:

1、__cdecl

__cdecl调用约定又称为 C 调用约定,是 C/C++ 语言缺省的调用约定。表示C语言默认的函数调用方法,参数按照从右至左的方式入栈,函数本身不清理栈,此工作由调用者负责,返回值在EAX中。由于由调用者清理栈,所以允许可变参数函数存在,如int sprintf(char* buffer,const char* format,...);。

 

2、__stdcall

__stdcall 很多时候被称为 pascal 调用约定。是StandardCall的缩写,是C++的标准调用方式。pascal 语言是早期很常见的一种教学用计算机程序设计语言。所有参数从右到左依次入栈,如果是调用类成员的话,最后一个入栈的是this指针。这些堆栈中的参数由被调用的函数在返回时清除,使用的指令是 retnX,X表示参数占用的字节数,CPU在ret之后自动弹出X个字节的堆栈空间。称为自动清栈。函数在编译的时候就必须确定参数个数,并且调用者必须严格的控制参数的生成,不能多,不能少,否则返回后会出错。返回值在EAX中

 

3、__fastcall

顾名思义,__fastcall 的特点就是快,因为它通过 CPU 寄存器来传递参数。他用 ECX 和 EDX 传送前两个双字(DWORD)或更小的参数,剩下的参数按照从右至左的方式入栈,函数自身清理堆栈,返回值在 EAX 中。

 

4、naked

naked 是一个很少见的调用约定,一般不建议使用。编译器不会给这种函数增加初始化和清理代码,更特殊的是,你不能用return返回返回值,只能用插入汇编返回结果,此调用约定必须跟 __declspec 同时使用。例如定义一个求和程序,如__declspec(naked) int  add(int a,int b);。

 

5、__pascal

这是 pascal 语言的调用约定,跟 __stdcall 一样,参数按照从右至左的方式入栈,函数自身清理堆栈,返回值在EAX中。VC 中已经废弃了这种调用方式,因此在写 VC 程序时,建议使用 __stdcall 代替。

 

6、__thiscall

这是 C++ 语言特有的一种调用方式,用于类成员函数的调用约定。如果参数确定,this 指针存放于 ECX 寄存器,函数自身清理堆栈;如果参数不确定,this指针在所有参数入栈后再入栈,调用者清理栈。__thiscall 不是关键字,程序员不能使用。参数按照从右至左的方式入栈。

注意

_fastcall 和 __thiscall涉及的寄存器由编译器决定,因此不能用作跨编译器的接口。所以Windows上的COM对象接口都定义为_stdcall调用方式。

针对参数列表类型的函数。即可变参数函数:

为什么只有__cdecl的调用约定支持可变参数,而__stdcall就不支持?

实际上__cdecl和__stdcall函数参数都是从右到左入栈,它们的区别在于由谁来清栈,__cdecl由外部调用函数清栈,而__stdcall由被调用函数本身清栈, 显然对于可变参数的函数,函数本身没法知道外部函数调用它时传了多少参数,所以没法支持被调用函数本身清栈(__stdcall), 所以可变参数只能用__cdecll.

另外还要理解函数参数传递过程中堆栈是如何生长和变化的,从堆栈低地址到高地址,依次存储 被调用函数局部变量,上一函数堆栈桢基址,函数返回地址,参数1, 参数2, 参数3..

参数传递顺序

1.从右到左依次入栈:__stdcall__cdecl,__thiscall,__fastcall
2.从左到右依次入栈:__pascal

调用堆栈清理

1.调用者清除栈。
2.被调用函数返回后清除栈。
 
X64下
调用约定简化了:一律使用__fastcall,前四个参数用 RCX、RDX、R8 和 R9传递,除了这四个外加RAX、R10、R11,其他寄存器都是非易失的。
https://msdn.microsoft.com/zh-cn/library/ms235286.aspx
 

最新文章

  1. 响应式Web设计 - 布局
  2. 在MyBook Live上部署svn
  3. GDB调试笔记
  4. Storm系列(十一)架构分析之Supervisor-管理Worker进程的事件线程
  5. HDOJ 1070 Milk(水题,考英文的)
  6. cocos2d-js(二)cocos2d-js的基本语法与类的简介
  7. Centos 搭建邮箱系统
  8. sklearn数据库-【老鱼学sklearn】
  9. 骨灰级玩家体验带你测试体验天使纪元OL折扣端
  10. 递归可视化之汉诺塔的动画实现(turtle海龟)
  11. ML.NET 示例:回归之价格预测
  12. MongoDB与关系型数据库 区别
  13. crontab使用说明及例子程序
  14. java空指针异常
  15. Linux动态共享库
  16. VMware + LInux + Xshell 连接环境设置(心得体会)
  17. django创建第一个项目helloworld
  18. bzoj 3144 [Hnoi2013]切糕——最小割
  19. DataGridView,Dataset,DataTable,DataRow等使用心得
  20. Unity 2D游戏开发教程之为游戏场景添加多个地面

热门文章

  1. C#在Linux上的开发指南(续)
  2. java线程基础知识----java线程模型
  3. Docker小白使用笔记
  4. [CentOS7] 设置开机启动方式(图形界面或命令行)
  5. select下拉框如何与接口配合动态生成option选项
  6. Python中的循环语句
  7. 飘逸的python - 单例模式乱弹
  8. Pod中spec的字段常用字段及含义
  9. Windows平台Anaconda使用笔记
  10. POJ1046 Color Me Less