三者都称为调用约定( Calling convention )
1)决定函数参数的压栈顺序
2)由调用者还是被调用者把参数弹出栈
3)编译产生函数名的方式
__stdcall 程序如果使用了__stdcall 关键字,或者设置了/Gz 编译选项,__stdcall 这种调用方式就会生效,WIN32 API都采用__stdcall调用方式。
- 函数参数采用从右到左的压栈方式;
- 被调函数在返回前自己清空堆栈;
- 输出函数名前面加下划线,后面加“@”符号和参数的字节数,如_funname@123。
__cdecl 程序如果使用了__cdecl关键字,或者设置了/Gd 编译选项(C/C++的缺省调用方式),__cdecl调用方式会生效。
- 函数参数采用从右到左的压栈方式;
- 传送参数的内存栈由调用者维护,每一个调用它的主调函数都包含清空堆栈的代码;
- 输出函数名仅在函数名前加下划线,如:_funname;
- 由于_cdecl调用方式的参数内存栈由调用者维护,所以变长参数的函数能(也只能)使用这种调用约定,比如 printf(const char*,...);
__fastcall 程序如果使用了__fastcall 关键字,或者设置了/Gr 编译选项,__fastcall 调用方式会生效。
- 它通过CPU内部寄存器ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送;
- 被调用的函数在返回前清理传送参数的内存栈;
- __fastcall调用约定在输出函数名前面加“@”符号,后面加“@”符号和参数的字节数,形如@funcname@123