一、函数调用约定
当参数个数多于一个时,按照什么顺序把参数压入堆栈函数调用后,由谁来把堆栈恢复原装。在高级语言中,通过函数调用约定来说明这两个问题。常见的调用约定有:
stdcall,cdecl,fastcall,thiscall,naked call
__stdcall、__cdecl和__fastcall是三种函数调用协议,函数调用协议会影响函数参数的入栈方式、栈内数据的清除方式、编译器函数名的修饰规则等(区别主要体现在编译成的汇编语言上)。
__stdcall:Windows API默认的函数调用协议。
__cdecl:C/C++默认的函数调用协议。
__fastcall:适用于对性能要求较高的场合。
二、C语言编译器函数名称修饰规则
__stdcall:编译后,函数名被修饰为"[email protected]"。
__cdecl:编译后,函数名被修饰为"_functionname"。
__fastcall:编译后, 函数名给修饰为"@[email protected]"。
注:"functionname"为函数名,"number"为参数字节数。
注:函数实现和函数定义时如果使用了不同的函数调用协议,则无法实现函数调用。
三、C++语言编译器函数名称修饰规则
__stdcall:编译后,函数名被修饰为"?functionname@@YG******@Z"。
__cdecl:编译后,函数名被修饰为"?functionname@@YA******@Z"。
__fastcall:编译后,函数名被修饰为"?functionname@@YI******@Z"。
注:"******"为函数返回值类型和参数类型表。
注:函数实现和函数定义时如果使用了不同的函数调用协议,则无法实现函数调用。 C语言和C++语言间如果不进行特殊处理,也无法实现函数的互相调用。
四、动态链接库的处理
EAPI int add(int a, int b);
其中EAPI的定义如下:
#ifdef DYNAMIC_EXPORT
#define _API_ __declspec(dllexport)
#else
#define _API_ __declspec(dllimport)
#endif
#define EAPI extern "C" _API_
如果定义了DYNAMIC_EXPORT宏,则API表示导出接口,否则表示导入接口;
而 #define EAPIextern “C” API
表示以C的方式导出(导入)接口。我们在这三个工程中都加入DYNAMIC_EXPORT预编译宏,表示导出接口;而在使用这三个工程(库)的工程(如VisualStudio)中不加DYNAMIC_EXPORT宏,表示导入接口。
五、函数的调用过程
要深入理解函数调用约定,你须要了解函数的调用过程和调用细节。 假设函数A调用函数B,我们称A函数为”调用者”,B函数为“被调用者”。如下面的代码,ShowResult为调用者,add为被调用者。
int add(int a, int b)
{
return a + b;
}
void ShowResult()
{
std::cout << add(5, 10)<< std::endl;
}
函数调用过程可以这么描述:
(1)先将调用者(A)的堆栈的基址(ebp)入栈,以保存之前任务的信息。
(2)然后将调用者(A)的栈顶指针(esp)的值赋给ebp,作为新的基址(即被调用者B的栈底)。
(3)然后在这个基址(被调用者B的栈底)上开辟(一般用sub指令)相应的空间用作被调用者B的栈空间。
(4)函数B返回后,从当前栈帧的ebp即恢复为调用者A的栈顶(esp),使栈顶恢复函数B被调用前的位置;然后调用者A再从恢复后的栈顶可弹出之前的ebp值(可以这么做是因为这个值在函数调用前一步被压入堆栈)。这样,ebp和esp就都恢复了调用函数B前的位置,也就是栈恢复函数B调用前的状态。
此部分内容参考:http://blog.csdn.net/zsy2020314/article/details/9429707
六、 VS设置默认的调用约定
C/C++默认的调用约定是__cdecl,那能不能修改这个默认的调用约定呢? 答案是肯定的。假设你有一个工程名叫VisualStudio,你想让这个工程下的所有函数默认都使用__stdcall,右键工程->Properties->ConfigurationProperties->C/C++->Advanced->Calling Convention,将其设置为__stdcall即可。
参考链接:
https://blog.csdn.net/luoweifu/article/details/52425733
https://blog.csdn.net/luoweifu/article/details/52456407