1.
函数调用约定,主要约束两件事
:
- 参数传递顺序;
- 调用堆栈由谁(调用函数或被调用函数)清理
2. 常用函数调用约定:
stdcall, cdecl,
fastcall, thiscall, naked call
3. __stdcall表示:
- 参数从右向左压入堆栈;
- 函数被调用者清理堆栈;
- C编译器函数名的修饰规则为:__functionname@number;(functionname为函数名,number为参数字节数)
- C++编译器函数名的修饰规则为:?functionname@@YG******@Z;(“******”为函数返回值类型和参数类型表)
- 使用场合:Windows API默认函数调用协议;
4. __cdecl表示
- 参数从右向左压入堆栈;
- 函数调用者清理堆栈;
- C编译器函数名的修饰规则为:__functionname;(functionname为函数名,number为参数字节数)
- C++编译器函数名的修饰规则为:?functionname@@YA******@Z;(“******”为函数返回值类型和参数类型表)
- 使用场合:C/C++默认函数调用协议;
PS:
- 函数实现和定义若使用不同的函数调用协议,则无法实现函数调用。
- C语言和C++语言间若不进行特殊处理,也无法实现函数的互相调用。
实践举例:VS下查看调用约定
例子:
(1)__stdcall:WIN API约定,参数由右向左传递,由被调者清理堆栈;
编译后函数名为:_func@参数字节数(C编译);
(2)__cdcel:C/C++约定,参数由右向左传递,由调用者清理堆栈;
c编译后的函数名为:_func,
c++编译后的函数名为:_func@参数修饰串
这里的清理堆栈,是指对参数的清理,可通过反汇编查看。调用函数内部的参数由内部自己处理。
2. 函数名修饰
作用:用于修饰函数在编译后的函数名符号
extern "C":C风格函数名,在编译后函数名不变
C编译:
C++编译:
总结:不同的函数名修饰,导致函数符号不一致,从而使得函数重载的实现成为可能。在extern "C"的修饰方式下,是不允许函数重载的。