调用约定(calling convention)(转)

本文详细介绍了C++中常见的几种调用约定:__cdecl、__stdcall、__fastcall及thiscall等,包括它们如何影响函数参数的压栈顺序、清理栈的责任方以及函数修饰名的生成规则,并给出了具体的应用场景。

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

       转自http://blog.sina.com.cn/qingsong80

        __cdecl__fastcall与 __stdcall,三者都是定(Calling Convention),它决定以下内容:
     
1) 函数参数的压栈顺
     
2) 用者是被用者把参数
     
3) 以及生函数修名的方法。

        1 __stdcall 定:函数的参数自右向左通 过栈传递 ,被 用的函数在返回前清理 送参数的内存
     
2 、_ _ cdecl 是C和C++程序的缺省 用方式。 一个 用它的函数都包含清空堆 的代 ,所以 生的可 行文件大小会比 用_stdcall函数的大。 函数采用从右到左的 压栈 方式。
      
注意: 于可 参数的成 函数,始 使用 __cdecl 转换 方式。
     
3 __fastcall 定:它是通 寄存器来 送参数的( 实际 上,它用 ECX EDX 送前两个双字( DWORD )或更小的参数,剩下的参数仍旧自右向左 压栈传 送,被 用的函数在返回前清理 送参数的内存 )。
     
4 thiscall 仅仅应 用于 "C++" 函数。 this 存放于CX寄存器,参数从右到左 。thiscall不是 关键词 ,因此不能被程序 指定。
     
5 naked call 采用 1-4 ,如果必要的 入函数 时编译 器会 生代 来保存 ESI EDI EBX EBP 寄存器,退出函数 时则产 生代 复这 些寄存器的内容。 naked call 这样 的代 。naked call不是 型修 符,故必 和_declspec共同使用。
     
定可以通 工程 置:Setting.../C/C++ /Code Generation 项进 选择 ,缺省状 态为 __cdecl
 
      名字修 饰约 定:
1 、修 名(Decoration name):"C"或者"C++"函数在内部( 编译 接)通 识别
2 C 编译时 函数名修 饰约 规则
__stdcall 定在 出函数名前加上一个下划 线 ,后面加上一个"@"符号和其参数的字 数,格式 _functionname@number 例如:function(int a, int b),其修 :_function@8
__cdecl 出函数名前加上一个下划 线 ,格式 _functionname
__fastcall 定在 出函数名前加上一个"@"符号,后面也是一个"@"符号和其参数的字 数,格式 @functionname@number
3 C++ 编译时 函数名修 饰约 规则
__stdcall 定:
1) 、以 "?" 标识 函数名的 始,后跟函数名;
2) 、函数名后面以"@@YG" 标识 参数表的 始,后跟参数表;
3) 、参数表以代号表示:
X--void
D--char
E--unsigned char
F--short
H--int
I--unsigned int
J--long
K--unsigned long
M--float
N--double
_N--bool
PA-- 表示指 ,后面的代号表明指 针类 型,如果相同 型的指 针连续 ,以 "0" 代替,一个 "0" 代表一次重
4) 、参数表的第一 项为该 函数的返回 值类 型,其后依次 参数的数据 , 针标识 在其所指数据 型前;
5) 、参数表后以"@Z" 标识 整个名字的 束,如果 函数无参数, 以"Z" 标识结 束。
其格式 "?functionname@@YG*****@Z" 或"?functionname@@YG*XZ,例如"
int Test1(char *var1,unsigned long)----"?Test1@@YGHPADK@Z"
     void Test2()-----“?Test2@@YGXXZ”
 
__cdecl 定:
规则 同上面的_stdcall 定,只是参数表的 标识 由上面的"@@YG" 变为 "@@YA"
 
__fastcall 定:
规则 同上面的_stdcall 定,只是参数表的 标识 由上面的"@@YG" 变为 "@@YI"
VC++ 函数的省缺声明是 "__cedcl", 将只能被 C/C++ 用。
 
注意:
1 、_beginthread需要__cdecl的 线 程函数地址,_beginthreadex和CreateThread需要__stdcall的 线 程函数地址。
2 、一般WIN32的函数都是__stdcall。而且在Windef.h中有如下的定
#define CALLBACK __stdcall
#define WINAPI   __stdcall
3 、extern "C" _declspec(dllexport) int __cdecl Add(int a, int b);
typedef int (__cdecl *FunPointer)(int a, int b);
符的 序如上。
4 extern "C" 的作用:如果 Add(int a, int b) 是在 c 编译 编译 ,而在 c++ 文件使用, 需要在 c++ 文件中声明: extern "C" Add(int a, int b) ,因 c 编译 器和 c++ 编译 函数名的解 不一 c++ 编译 器解 函数名的 候要考 函数参数, 这样 是了方便函数重 ,而在 c 言中不存在函数重 问题 ),使用 extern "C" 实质 就是告 c++ 编译 器, 函数是 c 里面的函数。 如果不使用extern "C" 会出 现链 错误
一般象如下使用:
#ifdef _cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C extern
#endif
#ifdef _cplusplus
extern "C"{
#endif
EXTERN_C int func(int a, int b);
#ifdef _cplusplus
}
#endif
5 、MFC提供了一些宏,可以使用AFX_EXT_CLASS来代替__declspec(DLLexport),并修 饰类 名,从而 ,AFX_API_EXPORT来修 函数,AFX_DATA_EXPORT来修 饰变
AFX_CLASS_IMPORT :__declspec(DLLexport)
AFX_API_IMPORT :__declspec(DLLexport)
AFX_DATA_IMPORT :__declspec(DLLexport)
AFX_CLASS_EXPORT :__declspec(DLLexport)
AFX_API_EXPORT :__declspec(DLLexport)
AFX_DATA_EXPORT :__declspec(DLLexport)
AFX_EXT_CLASS :#ifdef _AFXEXT
AFX_CLASS_EXPORT
#else
AFX_CLASS_IMPORT
6 、DLLMain 负责 初始化(Initialization)和 束(Termination)工作, 当一个新的 程或者 该进 程的新的 线 访问 DLL ,或者 访问 DLL 一个 程或者 线 程不再使用DLL或者 ,都会 用DLLMain。但是,使用TerminateProcess或TerminateThread 程或者 线 程,不会 用DLLMain。
7 、一个 DLL 在内存中只有一个
DLL 程序和 用其 出函数的程序的 系:
1) DLL 程、 线 程之
DLL 被映射到 用它的 程的虚 地址空
DLL 使用的内存从 程的虚 地址空 分配,只能被 该进 程的 线 程所 访问
DLL 的句柄可以被 程使用; 程的句柄可以被 DLL 使用。
DLL 可以有自己的数据段,但没有自己的堆 ,使用 程的 ,与 用它的 用程序相同的堆 模式。
2) 于共享数据段
DLL 的全局 量可以被 访问 DLL 可以 访问调 程的全局数据。 使用同一DLL的 一个 程都有自己的DLL全局 例。如果多个 线 程并 发访问 同一 量, 需要使用同 机制; 一个DLL的 量,如果希望 个使用DLL的 线 程都有自己的 则应该 使用 线 程局部存 (TLS ,Thread Local Strorage)。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值