__cdecl、__stdcall、__fastcall
1.这三个修饰符的基本意思__cdecl:C调用方式,VC默认使用该方式,参数从右向左传递,参数个数可变,栈的初始和清理由调用者完成
__stdcall:标准调用方式,多种语言使用这种调用方式,参数从右向左传递,参数个数不可变,栈的初始和清理由被调用者完成
__fastcall:参数尽量使用寄存器传递,很少用到,这里不予讨论。
2.这三个修饰符的使用位置
这三个修饰符要用在类型名之后,不能用在类型名之前,否则语法无法识别,容易被编译器误以为是默认int错误。
这三个修饰符都不能用于变量,如果使用会有警告,如下:


C 和C++ 对应不同的调用约定,产生的修饰符也各不相同,对于函数test(void)如下:
调用约定 | extern "C" 或 .c 文件 | .cpp、.cxx 或 /TP |
---|---|---|
C 命名约定 (__cdecl) |
_test |
?test@@ZAXXZ |
Fastcall 命名约定 (__fastcall) |
@test@0 |
?test@@YIXXZ |
标准调用命名约定 (__stdcall) |
_test@0 |
?test@@YGXXZ |
第三列,也就是CPP风格的情况下,修饰符有些复杂,以后补充吧。
以前面的一片随笔PureDllApp为例,VC9.0进行分析:
1、extern "C"作用下:
(1)__cdecl作用下(由于VC默认就是这种调用方式,所以这里就不给出代码,和前面的一片PureDllApp的代码一样):
PureApp.exe对PureDll.dll的导入修饰符如下:























需要注意的就是调用修饰符只能用在函数和成员函数的前面,而且要在返回值类型之后的位置。













































PureApp.exe对PureDll.dll的导入修饰符如下:






















比较上面的两组之间的差别,就可以发现__cdecl和__stdcall之间的差别。
第一点,构造函数在这两种调用方式中的产生的修饰符相同,其实产生的修饰符不是这两种的任何一种,而是__thiscall的修饰符,从PureDll.lib的后面括号中可以看出来,而且VC9.0中在构造函数前面使用__cdecl会直接产生编译时警告c4166,如下:






其实__thiscall和__stdcall差别不大,都是被调用者控制栈的初始和清理,只不过前者的this指针放在寄存器中,而后者的放在栈里。所以对于成员函数一般不要指定调用方式,使用默认的__shicall即可,除非要做参数数量可变的成员函数,不过这种函数尽量避免。
最后补充上setValue函数的__cdecl调用方式产生的修饰符:

2.对应上面的extern "C",下面是cpp(去掉extern "C")下对应上面的修饰符:
(1)__cdecl作用下:
PureApp.exe对PureDll.dll的导入修饰符如下:






















PureApp.exe对PureDll.dll的导入修饰符如下:






















补充一个强制指定__cdecl的setValue的修饰符:

cpp的__stdcall也没有什么特别的,和extern "C"相比,没有什么大的变化,唯一变得就是后面的字母变多了。而且能够发现无论是否存在extern "C",成员函数的修饰符都没有改变,这是因为C语言本身没有成员函数,所以extern "C对成员函数是无效的。
所以成员函数有两个特殊点:首先是extern "C"对类无效,即成员函数无效,其次是成员函数默认是__thiscall,除非在函数前强制指明其他调用方式。
暂时到这里,以后有机会再补充别的。