函数调用方式
“没见过在C语言中调用C++的函数”、“C/C++不能调用Basic、Pascal语言的函数”
这又是一个奇天下之大怪的问题,“打死我都不相信C、C++、basic、pascal的函数能瞎调来调去”,可是有句话这么说:没有你见不到的,只有你想不到的!
既然芙蓉姐姐也有其闻名天下的道理,那么C、C++、Basic、Pascal的函数为什么就不能互相调用呢?
能!
你可以用Visual C++写一个DLL在Visual Basic、Delphi(Pascal的孙子,Object Pascal的儿子)中调用,也可以在Visual Basic、Delphi中写一个DLL在Visual C++中调用不是?
让我们来透过现象看本质。首先看看函数的调用约定(以Visual C++来说明):
(1) _stdcall调用
_stdcall是Pascal程序的缺省调用方式,参数采用从右到左的压栈方式,被调函数自身在返回前清空堆栈。
WIN32 Api都采用_stdcall调用方式,这样的宏定义说明了问题:
#define WINAPI _stdcall
按C编译方式,_stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数,形如_functionname@number。
(2) _cdecl调用
_cdecl是C/C++的缺省调用方式,参数采用从右到左的压栈方式,传送参数的内存栈由调用者维护。_cedcl约定的函数只能被C/C++调用,每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。
由于_cdecl调用方式的参数内存栈由调用者维护,所以变长参数的函数能(也只能)使用这种调用约定。
由于Visual C++默认采用_cdecl 调用方式,所以VC中中调用DLL时,用户应使用_stdcall调用约定。
按C编译方式,_cdecl调用约定仅在输出函数名前面加下划线,形如_functionname。
(3) _fastcall调用
_fastcall调用较快,它通过CPU内部寄存器传递参数。
按C编译方式,_fastcall调用约定在输出函数名前面加“@”符号,后面加“@”符号和参数的字节数,形如@functionname@number。
关键字_stdcall、_cdecl和_fastcall可以直接加在函数前,也可以在Visual C++中设置,
在创建DLL时,一般使用_stdcall调用(Win32 Api方式),采用_functionname@number命名规则,因而各种语言间的DLL能互相调用。也就是说,DLL的编制与具体的编程语言及编译器无关,只要遵守DLL的开发规范和编程策略,并安排正确的调用接口,不管用何种编程语言编制的DLL都具有通用性。
推而广之,如果有这样一个IDE开发环境,它能识别各种语言,所有语言采用相同的调用约定和命名规则,一个软件内各种语言书写的函数将能互相调用!
这个世界上可能永远不需要这样一个IDE。