跨语言的C函数调用

来源:互联网 发布:ubuntu怎么安装程序 编辑:程序博客网 时间:2024/06/08 11:55

这两天被一个DLL的问题困惑了一把,
就是如何编译一个DLL,使之在VC、VB中都能使用。
(下面的描述基于Visual Studio 6.0 sp5,DLL中导出的都是标准C实现的函数)

以前偶在VC中写DLL的函数时都是这样:
假如有一个Extest()函数需要导出,就写
extern "C" __declspec(dllexport) int Extest()

在VC中使用该DLL时,如果需要调用刚才的Extest(),就写
extern "C" __declspec(dllimport) int Extest()
然后在程序中就可以用Extest()了。

这一次,当我在VB的工程中需要调用这个DLL的Extest()时,我先声明:
Declare Function Extest Lib "mydll.dll" () As Integer
然后在程序中调用Extest(),
但是调用完之后总是报一个"Run-time error '49'",
说是"Bad DLL calling convention"。

经过在MSDN中的一通查找,问题已解决,方法如下:

DLL的编写及导出方式
* 在VC中编写DLL的函数这样写:
  extern "C" int _stdcall Extest()
* 然后在该工程DEF文件的EXPORTS中加入:Extest

在VC中声明如下,即可使用
extern "C" int _stdcall Extest();

在VB中声明如下,即可使用
Declare Function Extest Lib "mydll.dll" () As Integer

解释两个问题

一、“_stdcall”的作用
  
在C/C++中函数默认Calling Conventions是:
参数由右向左压入栈,由调用者清空栈。,
在FORTRAN、PASCAL、BASIC等语言中,函数的Calling Conventions是:
参数由右向左压入栈,由被调函数清空栈。

那么在C/C++中使用_stdcall声明函数,
就可以指定C/C++按照FORTRAN等的约定使用函数,
当在FORTRAN等其它语言中调用这些函数就不会出现异常了,
这就是困扰偶的关键了:)


二、加“extern "C"”的作用
   
    extern "C" int _stdcall Extest();
    如上的原型,函数名符号会被VC编译器处理为 _Extest@0
   
    int _stdcall Extest();
    如上的原型,函数名符号会被VC编译器处理为 ?Extest@@YGXXZ
   
    C语言的编译链接环境不能处理第二种方式的修饰名,所以如果你的DLL
要在C和C++的环境下都适用,那么应该使用第一种命名方式。

原创粉丝点击