c与c++程序连接问题 (转)

它们之间的连接问题主要是因为c\c++编绎器对函数名译码的方式不能所引起的,考虑下面两个函数 
/* c*/ 
int strlen(char* string) 
{ ... } 
//c++ 
int strlen(char* string) 
{ ... } 
两个函数完全一样。在c在函数是通过函数名来识别的,而在C++中,由于存在函数的重载问题,函数的识别方式通函数名,函数的返回类型,函数参数列表三者组合来完成的。因此上面两个相同的函数,经过C,C++编绎后会产生完全不同的名字。所以,如果把一个用c编绎器编绎的目标代码和一个用C++编绎器编绎的目标代码进行连接,就会出现连接失败的错误。
解决的方法是使用extern C,避免C++编绎器按照C++的方式去编绎C函数 在头文件中定义: extern "C" int strlen(char* string) 或 extern "C" { int strlen(char* string) } 当C编绎器遇到extern "C"的时候就用传统的C函数编译方法对该函数进行编译。由于C编绎器不认识extern "C"这个编绎指令,而程序员又希望C,C++程序能共用这个头文件,因此通常在头文件中使用_cplusplus宏进行区分: 

#if define _cplusplus 
extern "C"{
#endif
int strlen(char* string)
#ifdefine _cplusplus
}
#endif

 #define CALLBACK     __stdcall

 #define WINAPI       __stdcall
  那么,除了__stdcall,还有别的调用类型吗?究竟什么是调用类型呢?我的理解是:调用类型就是如何使用函数参数的一种规则。有三种调用类型:__fastcall__cdecl__stdcall
1
__cdecl调用类型:
   
这是C的调用规则。对于所有非C++成员函数或未标有__stdcall__fastcall的函数来说,这是默认调用规则。
2
__fastcall调用类型:
   
从字面意思可知,这是一种快速调用。因为CPU的寄存器会被使用来存放函数参数列表中的头几个参数。而剩下参数将被从右至左地推倒堆栈上。被调用函数将从 寄存器和堆栈获得函数参数。在x86中,ECXEDX一般被用来存放开始的参数。在.NET中,为了性能上的快速,就是使用ecxedx来实现 __fastcall的。
3
__stdcall调用类型:
   
该调用只是通过堆栈来pushpop参数。push参数时,顺序是从右到左。

现在,你应该明白了吧。最后,我带一句。三种调用类型在VC编译器中对应/Gd/Gr/Gz三个编译选项


调用C/C++制做的DLL文件中导出函数的几点说明
用某种语言调用C/C++制做的DLL文件中导出函数时,有几点注意:一、“_stdcall”的作用 
C/C++中函数默认Calling Conventions(调用约定)是:
参数由右向左压入栈,由调用者清空栈。,
FORTRANPASCALVisualBASIC等语言中,函数的Calling Conventions是:
参数由右向左压入栈,由被调函数清空栈。 

那么在C/C++中使用_stdcall声明导出函数,就可以指定C/C++按照FORTRAN等的调用约定申明该函数,这时FORTRAN等其它语言中再调用这些函数就不会出现报错:run-time '49':Bad DLL call conventions. 

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

例如:MFC的类中调用自己写的C函数,有时出现错误说无法找到函数的定义,原因是由于C C++的编译器对函数的修饰名不同,C++的修饰名中包括了各参数类型,因此通常情况下,C++程序无法找到C库中的函数,需要在声明C函数时加上 extern "C"的说明: 

extern "C" void foo();
C++
编译器就会用C的修饰名方式来进行连接调用。同样,当C需要调用C++函数时,该C++函数也必须声明为extern "C"。通常可以在C的头文件里这样定义:

#ifdef __cplusplus extern "C" { #endif ... #ifdef __cplusplus } #endif
就可兼容CC++程序。

原文链接:http://hi.baidu.com/yebihaigsino/blog/item/8efd3bd8ca21c8ee39012f0f.html

posted on 2011-07-30 19:53  xuangong  阅读(620)  评论(0编辑  收藏  举报

导航