函数的调用约定有哪些,区别是什么

1. cdecl (C Declaration)

这是 C 语言的默认调用约定,也是最常见的

  • 参数传递:从右到左依次推入栈中
  • 栈清理:由调用方(caller)负责在函数返回后清理栈
  • 寄存器eax, ecx, edx 是调用方保存的(caller-saved)寄存器。这意味着被调用函数可以自由使用这些寄存器,如果调用方需要保存它们,需要在调用前自己推入栈中

优点:支持可变参数函数,例如 printf

缺点:每次函数调用后都需要调用方执行额外的栈清理指令,会增加代码大小

2. stdcall (Standard Call)

这是 Windows API 的默认调用约定

  • 参数传递:从右到左依次推入栈中
  • 栈清理:由被调用方(callee)负责清理栈
  • 寄存器:与 cdecl 类似

优点:代码更精简。由于被调用方知道参数数量,只需一条指令即可清理栈

缺点:不支持可变参数函数,因为被调用方需要知道参数数量才能正确清理栈

3. fastcall

这是一个为了提高性能而设计的调用约定

  • 参数传递:前两个(或更多,具体取决于编译器和架构)参数通过寄存器传递,而不是通过栈。其余参数从右到左推入栈中
  • 栈清理:由被调用方清理栈
  • 寄存器:使用 ecxedx(在 32 位 Windows 上)或 rcxrdx(在 64 位 Windows 上)来传递前两个参数

优点:通过减少内存访问(栈操作)来提高函数调用速度

缺点:不支持可变参数函数

4. thiscall

这是 C++ 中非静态成员函数的默认调用约定

  • 参数传递:与 cdeclstdcall 类似,但隐藏的 this 指针(指向对象实例)通过寄存器传递
  • 栈清理:由被调用方清理栈

优点:优化了 C++ 成员函数的调用

缺点:只能用于 C++ 成员函数

5. pascal (Pascal Language)

在老旧的 Windows 16 位编程中很常见,现在很少使用

  • 参数传递:从左到右推入栈中
  • 栈清理:由被调用方清理栈

不同平台下的调用约定

  • Windows (x86)
    • cdecl:C/C++ 默认
    • stdcall:Windows API 默认
    • fastcall:用于性能优化
    • thiscall:C++ 成员函数
  • Windows (x64)
    • __fastcall:这是 64 位 Windows 的唯一调用约定。前四个整数或指针参数通过 rcx, rdx, r8, r9 寄存器传递。其余参数从右到左推入栈中
  • Linux (x86)
    • cdecl:默认
  • Linux (x64)
    • 前六个整数或指针参数通过 rdi, rsi, rdx, rcx, r8, r9 寄存器传递。其余参数从右到左推入栈中
Copyright © 版权信息 all right reserved,powered by Gitbook该文件修订时间: 2025-09-25 03:13:09

results matching ""

    No results matching ""