了解常用的C/C++函数调用约定


什么是函数调用约定?

调用约定(Calling convention)决定以下内容:

  • 函数参数的压栈顺序
  • 由调用者还是被调用者把参数弹出栈
  • 产生函数修饰名的方法。

关于 C/C++ 函数调用约定,大多数时候并不会影响程序逻辑,但遇到跨语言编程时,了解一下还是有好处的。

  VC 中默认调用是 __cdecl 方式,Windows API 使用 __stdcall 调用方式,在 DLL 导出函数中,为了跟 Windows API 保持一致,建议使用 __stdcall 方式。

调用约定跟堆栈清除密切相关。如果写一个汇编函数,给 C/C++ 调用,在 __cdecl 方式下,则汇编函数无需清除堆栈,在 __stdcall 方式下,汇编函数需要在返回(RET)之前恢复堆栈。

MFC支持以下调用约定:

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

常用6种描述编辑

__cdecl

按从右至左的顺序压参数入栈,由调用者把参数弹出栈。

  • 对于“C”函数或者变量,修饰名是在函数名前加下划线。(如函数void test(void)的修饰名是_test)
  • 对于“C++”函数,有所不同。 (对于不属于一个类的“C++”全局函数,修饰名是?test@@ZAXXZ。)

这是MFC缺省调用约定。由于是调用者负责把参数弹出栈,返回值在EAX中,所以可以给函数定义个数不定的参数,如printf函数。

__stdcall

  __stdcall 很多时候被称为 pascal 调用约定。pascal 语言是早期很常见的一种教学用计算机程序设计语言,其语法严谨。参数按照从右至左的顺序压参数入栈,由被调用者把参数弹出栈,返回值在EAX中。所有的Win32 API函数都遵循该约定。

__fastcall

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

__thiscall

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

naked

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

__pascal

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值