调用约定
- 来源: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgCallingConventions
- 最后更新: 2016-03-13
指定过程的调用方式。
调用约定决定调用代码在调用过程时如何与过程交互。它们规定了参数如何压入调用栈、值如何返回以及何时清理调用栈的规则。这些信息在与其他语言(尤其是汇编语言)编写的代码交互时非常有用。在某些情况下,调用约定还对过程名称进行某种名称修饰。
FreeBASIC 支持 3 种调用约定:stdcall、cdecl 和 pascal,分别通过 Stdcall、Cdecl 和 Pascal 指定。调用约定可以在过程声明或定义中紧跟过程名称之后指定。过程的声明必须与定义具有相同的调用约定。
在所有调用约定中,整数过程返回值在 EAX(, EDX)寄存器中返回,浮点返回值存储在 ST(0) 寄存器中(浮点栈的顶部)。用户定义类型(UDT)值在 EAX(, EDX)寄存器中返回(如果不超过八(8)字节),否则通过将其地址压入调用栈(在任何参数之后)在内存中返回。
stdcall
在 stdcall 约定中,过程参数在过程调用之前以声明的相反顺序(即从右到左)压入调用栈(过程调用会将返回地址压入参数上方)。过程负责从调用栈中弹出任何参数(通常通过在 RET 指令后附加一个常量来指定要释放的字节数)。
stdcall 是 Windows 上的默认调用约定,以及 Extern "Windows" 和 Extern "Windows-MS" 块内过程的默认约定。它也是 Windows API 使用的默认约定。
平台差异
- 在 DOS 和 Windows 平台上,过程名称会添加 "
@N" 后缀,其中N是传递的任何参数的总字节大小。
cdecl
在 cdecl 约定中,过程参数在过程调用之前以声明的相反顺序(即从右到左)压入调用栈。调用代码负责从调用栈中弹出参数。
cdecl 是 Linux、*BSD 和 DOS 上的默认调用约定,以及 Extern "C" 和 Extern "C++" 块内过程的默认约定。它也是大多数 C 和 C++ 编译器使用的默认约定。
pascal
在 pascal 约定中,过程参数以声明的顺序(即从左到右)压入调用栈。过程负责从调用栈中弹出任何参数。
pascal 是 Pascal 和 Microsoft QuickBASIC 系列编译器使用的默认约定。
下表总结了各种调用约定之间的差异:
| 调用约定 | 参数压入调用栈的方向 | 从调用栈弹出参数的一方 |
|---|---|---|
| stdcall | 从右到左 | 过程 |
| cdecl | 从右到左 | 调用代码 |
| pascal | 从左到右 | 过程 |
平台差异
- 在 DOS 和 Windows 平台上,所有调用约定都会在过程名称前添加下划线(
"_")前缀。 - 默认调用约定因平台而异。Windows 上为 stdcall;而在 Linux、*BSD 和 DOS 上为 cdecl。
参见
Declare,Sub,FunctionStdcall,Cdecl,PascalExtern..End Extern
返回 目录