由数值审核还是由参考审核?
前者把整个的变量复制到堆栈上,这不但很慢而且如果变量很大,可能使堆栈无法承担。例如,10,000个数组会减少10,000个堆栈指数并且把这10,000个整数的值到复制到堆栈上。相比之下,使用参考审核则要快得多,因为它只会把变量的地址送到堆栈上。所以在C语言中是用指数(*),在c++中使用参考(&)来保持其简便。
调用约定
了解参数是很重要的,比方,a,b,c,它们是按照这个顺序送到堆栈的吗?还是按照c,b,a的顺序?返回地址会去到哪里呢?同样,被调用的函数从堆栈删除参数还是从主程序?为什么不从登记簿通过数值来加速呢?指定发生的事情就是调用约定所做的事。
约定列表
主要的约定如下所示。
function f(A, B, C)
- cdecl 这是C和C + +中默认的。参数从右到左推入,从C到B然后到A。所谓的函数得到各种参数值,但不会改变原来的堆栈,因此,编译器在增加堆栈的请求之后要增加一个指令,使其平衡。不同的平台之间在注册使用,一些语言方面有差别,如Visual Basic中不能使用cdecl 。但是它支持variadic函数,如printf()。
- stdcall 这可能是最常见的,当然,前提是涉及非C / C + +语言。与cdecl不同的是,参数从左至右推入而且函数本身必须清理堆栈后才能返回。
- winapi 如果未特别指定的话,这是Windows默认的。它在Windows CE上默认为stdcall和cdecl Windows CE。不过它和stdcall不一样,所以如果您尝试调用标为winapi的DLL函数,虽然你期待中是stdcall,但Windows是找不到它的。
- fastcall它使用登记簿加速,但是在不同的编译器中它算是别具一格的。所以如果你坚信来自某个源的编译器,而不是被要求出自某种语言,如Visual Basic或C # ,那就可以使用fastcall。
- safecall Borland公司用它来实现COM/OLE调用。
- thiscall 用于调用出自未管理代码分类出的函数。
除非你的dlls只被C或C++使用,否则的话,你就相信winapi。则会使默认情况,所以不需要指定。
C++中的名字改编
因为C + +语言是一种安全且相当严谨的语言类型,它提出了名字改编。这意味着,输出的函数,包括来自类型的参数类型的额外函数。这有助于防止函数被调用时出现参数错误,而这种错误可能会导致莫名的死机。然而,当非C + +代码调用C + +的函数时也可能会出现问题。例如,你有一个C #应用程序调用dll的C + =代码。由于dll中的函数名称毁坏,函数就无法被找到。操作系统可能会期望一个叫做GetValue(int a, float b)的函数,但在该dll中,名称错位后看起来就像GetValueif。
有一种简单的修复方法。任何C++ dll必须把代码在任何输出函数之前和之后的说明中。就像这样:
2 #ifdef __cplusplus
3 extern "C" {
4 #endif
5 MYEXPORT char * WINAPI GetBotName(void) ; // returns name of your Bot
6 #ifdef __cplusplus
7 }
8 #endif
这一行:#define MYEXPORT __declspec(dllexport),就告诉了编译器在任何由MYEXPORT定于的函数上添加_declspec。这使得该函数可见与使用dll的任何应用程序。
macro_cplusplus只定义在兼容C++编译器的Ansi 98中。所以macro会被所有包含在C文件夹的页眉文件忽视。
在你拥有C代码的反例中,你希望与C++链接,那样你就把说明用这个语句包装起来:
extern “C++” {
这一操作可迫使编译器粉碎函数名称。