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

1. `cdecl` (C Declaration)

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

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

优点：支持可变参数函数，例如 `printf`

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

2. `stdcall` (Standard Call)

这是 Windows API 的默认调用约定

- 参数传递：从右到左依次推入栈中
- 栈清理：由被调用方（callee）负责清理栈
- 寄存器：与 `cdecl` 类似

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

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

3. `fastcall`

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

- 参数传递：前两个（或更多，具体取决于编译器和架构）参数通过寄存器传递，而不是通过栈。其余参数从右到左推入栈中
- 栈清理：由被调用方清理栈
- 寄存器：使用 `ecx` 和 `edx`（在 32 位 Windows 上）或 `rcx` 和 `rdx`（在 64 位 Windows 上）来传递前两个参数

优点：通过减少内存访问（栈操作）来提高函数调用速度

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

4. `thiscall`

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

- 参数传递：与 `cdecl` 或 `stdcall` 类似，但隐藏的 `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` 寄存器传递。其余参数从右到左推入栈中