详解C/C++函数调用约定:从__cdecl到名字修饰

今天早睡
今天早睡
发布时间:2026-10-16| 4人浏览过
原创

C/C++编程中,函数调用约定决定了参数如何传递给函数以及由谁负责清理栈内存。了解__cdecl、__stdcall等约定的差异,以及C和C++编译器生成的不同名字修饰(Name Mangling)规则,是解决链接错误、实现DLL导出和进行底层调试的关键。

C/C++函数调用约定概览

在32位Windows平台下,C和C++提供了多种函数调用约定,它们定义了寄存器使用和堆栈操作的行为。

1. __cdecl (C Default Calling Convention)

__cdecl是C/C++语言的默认调用约定。其核心特征包括:

  • 参数入栈顺序:从右向左依次入栈。
  • 栈清理责任:由调用者负责清理堆栈。这使得它天然支持可变参数函数(如printf)。
  • 返回值:通常存放在EAX寄存器中。
  • 符号修饰:函数名前加下划线前缀。见下方名字修饰说明。
int __cdecl add(int a, int b) {
	int c = a + b;
	return c;
}

int main(void) {
	int x = 1, y = 2;
	int z = add(x, y);
	return 0;
}

2. __stdcall

__stdcall常见于Windows API函数。与__cdecl的区别在于:

  • 参数入栈:同样从右向左入栈。
  • 栈清理责任:由被调用函数自身在返回前清理堆栈(使用ret N指令,N为参数字节数)。
  • 返回值:存放于EAX寄存器。

3. __fastcall

旨在提高调用速度,通过CPU寄存器传递部分参数:

  • 参数传递:前两个双字(DWORD)或更小的参数分别通过ECX和EDX寄存器传递。
  • 剩余参数:按照从右向左的顺序入栈。
  • 栈清理:由被调用函数自身负责清理。

4. naked (裸函数)

naked不是一种独立的协议,必须结合其他约定使用(如_declspec(naked))。

  • 编译器不为该函数生成进入和退出代码(如保存/恢复寄存器、调整栈帧)。
  • 禁止使用return返回值,必须由程序员手动编写汇编来清理栈并返回结果。

5. __pascal

源自Pascal语言的古老调用约定。行为类似于__stdcall(参数逆序压栈,函数清理栈)。现代Visual Studio编译器已废弃此约定,开发中建议直接使用__stdcall。

6. __thiscall (C++特有)

专门用于C++类成员函数的调用约定:

  • this指针:始终放置在ECX寄存器中。
  • 参数入栈:其余参数按从右向左顺序入栈。
  • 栈清理:如果参数个数确定,由函数自身清理;如果不确定(如虚函数),通常由调用者处理。
class Object {
private:
	int value;
	int nums;
public:
	Object(int x = 0, int y = 0) : value(x), nums(y) {}
	void Print() const {
		std::cout << value << std::endl;
	}
};

int main(void) {
	Object obj(10, 20);
	obj.Print();
	return 0;
}

名字修饰约定

为了实现函数重载、区分不同的调用约定,编译器会对函数名进行“装饰”(Mangling),生成内部使用的唯一标识符。

1. C语言编译时的名字修饰规则

C语言不支持函数重载,修饰相对简单:

  • __cdecl:函数名前加一个下划线。例如add变为_add。
  • __stdcall:函数名前加下划线,后跟@符号和参数字节总数。例如fun(a, b)(两整数8字节)变为_fun@8。
  • __fastcall:函数名前加@符号,后接@符号及参数字节总数。例如fun(a)变为@fun@4。
// extern "C" 关闭名字修饰,保持原样输出供外部调用
extern "C" {
	int __stdcall fun1(int a, int b) { return 0; }
	int __cdecl fun2(int a) { return 0; }
	int __fastcall fun3(int a) { return 0; }
}

2. C++编译时的名字修饰规则

C++采用复杂的修饰算法以支持重载和类型安全,通常以?开头::

代号 含义
X void
H int
J long
PA 指针
Z 无参或结束标记
extern "C++" {
	// 以下仅为示意实际修饰名极长且复杂
	void __stdcall fun_int(int a); 
	// 类似 ?fun_int@@YGXH@Z 
}
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。