两者实质上是一致的,即
函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈,但不同的
是函数名的修饰部分(具体参见下一节介绍)。
C 调用约定(即用_cdecl 关键字说明)和_stdcall 调用约定有所不同,虽然在参数传送方
面是一样的,但C 调用约定对于传送参数的内存栈却是由调用者来维护的(也正因为如此,
实现可变参数的函数只能使用该调用约定),另外,在函数名修饰约定方面也有所不同。
_fastcall 调用约定的主要特点就是快,因为它是通过寄存器来传送参数的(实际上,它用
ECX 和EDX 传送前两个双字或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的
函数在返回前清理传送参数的内存栈),在函数名修饰约定方面,它和前两者均不同。
关键字_stdcall、_cdecl 和_fastcall 可以直接加在要输出的函数前,也可以在编译环境中选
择“Setting...|C/C++|Code Generation”菜单命令,在如图10-3 所示的对话框中设置编译环境。
当加在输出函数前的关键字与编译环境中的选择不同时,直接加在输出函数前的关键字有效。
它们对应的命令行参数分别为/Gz、/Gd 和/Gr。默认状态为/Gd,即_cdecl。
图10-3 编译环境设置
如果要完全模仿PASCAL 调用约定首先必须使用_stdcall 调用约定,至于函数名修饰约
定,可以通过其他方法模仿。另外需要注意的是Windows.h 支持WINAPI 宏,该宏可以将输
出函数翻译成适当的调用约定,在WIN32 中,它被定义为_stdcall。
2.函数名修饰约定
函数名修饰约定随编译种类和调用约定的不同而不同,下面分别说明。对于C 编译,
枫叶文学网www.fywxw.com
第10 章 动态链接库
·263·
_stdcall 调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的
字节数,格式为_functionncom@number。_cdecl 调用约定仅在输出函数名前加上一个下划线
前缀,格式为_functionncom。_fastcall 调用约定在输出函数名前加上一个“@”符号,后面
也是一个“@”符号和其参数的字节数,格式为@functionncom@number。它们均不改变输出
函数名中字符的大小写,这和PASCAL 调用约定不同,PASCAL 约定输出的函数名无任何修
饰且全部大写。本例将给出一种完全模仿PASCAL 调用约定的方法,在DEF 文件的EXPORTS
段通过别名来实现。例如:
int __stdcall MyFunc (int a,double b);
void __stdcall InitCode (void);
在DEF 文件中:
EXPORTS
MYFUNC=_MyFunc@12
INITCODE=_InitCode@0
Visual C++编译输出的函数名修饰较为复杂,编译时stdcall 调用