函数的__cdecl、__stdcall、__fastcall、__thiscall、naked call介绍

本文详细介绍了几种常见的函数调用约定,包括__cdecl、__stdcall、__fastcall、__thiscall和__declspec(naked),并解释了每种约定的参数传递方式、清栈责任及函数命名规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

调用方式:

__cdecl 是 C Declaration 的缩写,表示C语言默认的函数调用方法:所有参数从右到左依次入栈。这些参数在函数返回后由外部调用者清除,称为手动清栈。在外部使用add esp,x 平衡堆栈,x是参数所占的总字节数。利用此特性可以实现可变参数的函数功能。

__stdcall 是 Standard Call 的缩写,是C++的标准调用方式:所有参数从右到左依次入栈。如果用此方法调用类成员函数,最后一个入栈的是this指针。这些参数由函数自己内部在返回时清除,称为自动清栈。返回时使用retn x 平衡堆栈,x表示参数所占的总字节数。

__fastcall 是通过寄存器来传递参数的,利用 ECX 和 EDX 传送前两个双字(DWORD)或更小的参数。如果还有更多的参数,则从右到左依次入栈。这些由堆栈传送的参数,由函数自己内部在返回时清除,即自动清栈。返回时使用retn x 平衡堆栈,x表示使用堆栈传送的参数的总字节数。

__thsicall 是仅仅应用于C++成员函数。this指针存放于 ECX 寄存器(该寄存器由编译器指定),参数从右到左依次入栈,与__stdcall相同,返回时自动清栈。__thiscall 不是关键词,因此不能被程序员指定。在VC中编译器使用 ECX 传递,在Borland中使用 EAX 传递。

nake call 是裸函数调用方式。不对EBP、ESP做处理,函数体不做任何附带操作。用 __declspec(nake) 定义,调用方式依据编译器中,设定的默认调用约定方式设定。

调用名称约定:

__cdecl 是在函数名加上一个下划线前缀,格式为_functionname。

__stdcall 是在函数名加上一个下划线前缀,在边加上一个@符号和其参数的总字节数。

__fastcall 是在函数名加上一个@符号,在边也加上一个@符号和其参数的总字节数。

__thiscall 是在函数名加上类名和::符号。

nake call 是依据编译器设定的调用约定方式。

调用方式设定:

在VS中编译器缺省状态为/Gd,即__cdecl方式。__stdcall对应为/Gz,__fastcall对应为/Gr。

我们写段程序对比一下反汇编代码就能明白:

#define EXPORT __declspec(dllexport)
extern "C"{
	EXPORT void __cdecl FunA(int a, int b, int c){}
	EXPORT void __stdcall FunB(int a, int b, int c){}
	EXPORT void __fastcall FunC(int a, int b, int c){}
	class CClassA { public: void EXPORT __thiscall FunD(int a, int b, int c){} };
	EXPORT void __declspec(naked) FunE(int a, int b, int c){}
}
int __cdecl main(int argc, char* argv[])
{
	CClassA obj;
	FunA(1, 2, 3); // __cdecl
	FunB(1, 2, 3); // __stdcall
	FunC(1, 2, 3); // __fastcall
	obj.FunD(1, 2, 3); // __thiscall
	FunE(1, 2, 3); // naked call
	return 0;
}

对应的反汇编代码是:

	CClassA obj;
	FunA(1, 2, 3); // __cdecl
011514F8 6A 03                push        3  
011514FA 6A 02                push        2  
011514FC 6A 01                push        1  
011514FE E8 42 FC FF FF       call        _FunA (01151145h)  
01151503 83 C4 0C             add         esp,0Ch  
	FunB(1, 2, 3); // __stdcall
01151506 6A 03                push        3  
01151508 6A 02                push        2  
0115150A 6A 01                push        1  
0115150C E8 02 FC FF FF       call        _FunB@12 (01151113h)  
	FunC(1, 2, 3); // __fastcall
01151511 6A 03                push        3  
01151513 BA 02 00 00 00       mov         edx,2  
01151518 B9 01 00 00 00       mov         ecx,1  
0115151D E8 C9 FB FF FF       call        @FunC@12 (011510EBh)  
	obj.FunD(1, 2, 3); // __thiscall
01151522 6A 03                push        3  
01151524 6A 02                push        2  
01151526 6A 01                push        1  
01151528 8D 4D F7             lea         ecx,[obj]  
0115152B E8 B1 FB FF FF       call        CClassA::FunD (011510E1h)  
	FunE(1, 2, 3); // naked call
01151530 6A 03                push        3  
01151532 6A 02                push        2  
01151534 6A 01                push        1  
01151536 E8 14 FC FF FF       call        _FunE (0115114Fh)  
0115153B 83 C4 0C             add         esp,0Ch  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值