threemiles

博客园 首页 新随笔 联系 订阅 管理

举这样一个例子:

使用C语言创建一个dll库供C++客户端使用

 

C语言dll端

 

  dll.h

View Code
 1 #ifndef _DLL_H_
2 #define _DLL_H_
3
4 #if BUILDING_DLL
5 # define DLLIMPORT __declspec (dllexport)
6 #else
7 # define DLLIMPORT __declspec (dllimport)
8 #endif
9
10 DLLIMPORT int HelloWorld (const char * pStr);
11
12 #endif /** _DLL_H_ */

  dllmain.c(注意到后缀名是.C所以函数为按照C语言编译规则导出)

View Code
 1 #include "dll.h"
2 #include <Windows.h>
3 #include <stdio.h>
4
5 DLLIMPORT int HelloWorld(const char* pStr)
6
7 {
8 printf("%s\n",pStr);
9 return strlen(pStr);
10 }
11
12
13 BOOL APIENTRY DllMain (HINSTANCE hInst,
14 DWORD reason,
15 LPVOID reserved)
16 {
17 switch (reason)
18 {
19 case DLL_PROCESS_ATTACH:
20 break;
21 case DLL_PROCESS_DETACH:
22 break;
23 case DLL_THREAD_ATTACH:
24 break;
25 case DLL_THREAD_DETACH:
26 break;
27 }
28
29 return TRUE;
30
31 }

 

使用dumpbin -exports查看生成的dll文件

   

 

C++客户端

 

  dll.h

View Code
 1 #ifndef _DLL_H_
2 #define _DLL_H_
3
4 #if BUILDING_DLL
5 # define DLLIMPORT __declspec (dllexport)
6 #else
7 # define DLLIMPORT __declspec (dllimport)
8 #endif
9
10 DLLIMPORT int HelloWorld (const char * pStr);
11
12 #endif /** _DLL_H_ */

  main.cpp

View Code
1 #include "dll.h"
2
3 #pragma comment(lib,"externC_test.lib")
4
5 int _tmain(int argc, _TCHAR* argv[])
6 {
7   HelloWorld("Hello,World");
8   return 0;
9 }

 

结果编译链接时error LNK2019: 无法解析的外部符号 "__declspec(dllimport) int __cdecl HelloWorld(char const *)" (__imp_?HelloWorld@@YAHPBD@Z)

 

分析:

  C++支持函数重载,而C不支持,两者的编译规则也不一样。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为: void foo( int x, int y ); 该函数被C编译器编译后在符号库中的名字可能为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的

 

解决方法:

一、在C动态库端将dllmain.c的后缀名改为.cpp,使函数按照C++的编译规则导出,但不建议这样,这样一来使用C语言的客户端将不能调用该库

二、修改dll.h头文件,推荐使用该方法,这样不管是C客户端还是C++客户端 都可以调用该库

View Code
 1 #ifndef _DLL_H_
2 #define _DLL_H_
3
4 #if BUILDING_DLL
5 # define DLLIMPORT __declspec (dllexport)
6 #else
7 # define DLLIMPORT __declspec (dllimport)
8 #endif
9
10 #ifdef __cplusplus
11 extern "C" {
12 #endif
13
14 DLLIMPORT int HelloWorld (const char * pStr);
15
16 #ifdef __cplusplus
17 };
18 #endif
19
20 #endif /** _DLL_H_ */

再举一个例子(在一个工程中CC++语言混合使用)

 

ctest.c

View Code
1 #include <Windows.h>
2 #include <stdio.h>
3
4 int testFunc(const char* pStr)
5 {
6   printf("%s\n",pStr);
7   return strlen(pStr);
8 }

 

main.cpp

View Code
1 int testFunc(const char* pStr);
2
3 int main(int argc, char* argv[])
4 {
5   testFunc("hello,world");
6   return 0;
7 }

编译链接时 : error LNK2001: 无法解析的外部符号 "int __cdecl testFunc(char const *)" (?testFunc@@YAHPBD@Z)

 

修改main.cpp

View Code
1 extern "C" int testFunc(const char* pStr);
2
3 int main(int argc, char* argv[])
4 {
5 testFunc("hello,world");
6 return 0;
7 }

 

总结:

一、被extern "C"修饰的变量和函数是按照C语言方式编译和连接的

二、extern "C"的真实目的是 实现C++与C及其它语言的混合编程

三、注意在C语言的源文件.c中不能使用extern "C"

 

posted on 2011-08-04 15:47  threemiles  阅读(560)  评论(1)    收藏  举报