C中调用C++,C++中调用C都会用到extern "C",但两者的意义却大不一样!!


先介绍在C++中调用C,这个大家都比较熟悉:

例:

//C代码

  1. <span style="font-family:Microsoft YaHei;font-size:18px;">void foo( int x );  

  2. </span>  

<span style="font-family:Microsoft YaHei;font-size:18px;">void foo( int x );</span>

//C++代码

  1. <span style="font-family:Microsoft YaHei;font-size:18px;">//C++ code 

  2. extern"C"void foo( int x );  

  3. </span>  

<span style="font-family:Microsoft YaHei;font-size:18px;">//C++ codeextern "C" void foo( int x );</span>让C++连接器能通过过类似于_foo来查找此函数,而非类似于_foo_int这样的符号。



使用extern "C"则是告诉编译器依照C的方式来编译封装接口,当然接口函数里面的C++语法还是按C++方式编译。使用extern "C"则是告诉编译器依照C的方式来编译封装接口,当然接口函数里面的C++语法还是按C++方式编译。


再来说说C中调用C++,这其中也会用到extern "C",这则是告诉编译器依照C的方式来编译封装接口,当然接口函数里面的C++语法还是按C++方式编译。

C++代码:(非成员函数)

  1. <span style="font-family:Microsoft YaHei;font-size:18px;">extern"C"int foo( int x );  

  2. int foo( int x )  

  3. {  

  4. //... 

  5. }</span>  

<span style="font-family:Microsoft YaHei;font-size:18px;">extern "C" int foo( int x );int foo( int x ){//...}</span>这样,编译器会将foo函数编译成类似_foo符号,而不会编译成类似_foo_int符号。


C代码

 

  1. <span style="font-family:Microsoft YaHei;font-size:18px;">int foo( int x );  

  2. void cc( int x )  

  3. {  

  4.     foo( x );  

  5. //... 

  6. }</span>  

<span style="font-family:Microsoft YaHei;font-size:18px;">int foo( int x );void cc( int x ){foo( x );//...}</span>

 


如果你想要在 C 里调用成员函数(包括虚函数),则需要提供一个简单的包装(wrapper)。例如:

 

  1. <span style="font-family:Microsoft YaHei;font-size:18px;">// C++ code: 

  2. class C  

  3. {  

  4. // ... 

  5. virtualdouble f(int);  

  6. };  

  7. extern"C"double call_C_f(C* p, int i) // wrapper function 

  8. {  

  9. return p->f(i);  

  10. }</span>  

<span style="font-family:Microsoft YaHei;font-size:18px;">// C++ code:class C{// ...virtual double f(int);};extern "C" double call_C_f(C* p, int i) // wrapper function{return p->f(i);}</span>
然后,你就可以这样调用 C::f():

 

 

  1. <span style="font-family:Microsoft YaHei;font-size:18px;">/* C code: */

  2. double call_C_f(struct C* p, int i);  

  3. void ccc(struct C* p, int i)  

  4. {  

  5. double d = call_C_f(p,i);  

  6. /* ... */

  7. } </span>  

<span style="font-family:Microsoft YaHei;font-size:18px;">/* C code: */double call_C_f(struct C* p, int i);void ccc(struct C* p, int i){double d = call_C_f(p,i);/* ... */} </span>

 



如果你想在 C 里调用重载函数,则必须提供不同名字的包装,这样才能被 C 代码调用。例如:

 

  1. <span style="font-family:Microsoft YaHei;font-size:18px;">// C++ code: 

  2. void f(int);  

  3. void f(double);  

  4. extern"C"void f_i(int i) { f(i); }  

  5. extern"C"void f_d(double d) { f(d); } </span>  

<span style="font-family:Microsoft YaHei;font-size:18px;">// C++ code:void f(int);void f(double);extern "C" void f_i(int i) { f(i); }extern "C" void f_d(double d) { f(d); } </span>
然后,你可以这样使用每个重载的 f():

 


  1. <span style="font-family:Microsoft YaHei;font-size:18px;">/* C code: */

  2. void f_i(int);  

  3. void f_d(double);  

  4. void cccc(int i,double d)  

  5. {  

  6.        f_i(i);  

  7.        f_d(d);  

  8. /* ... */

  9. } </span>  

<span style="font-family:Microsoft YaHei;font-size:18px;">/* C code: */void f_i(int);void f_d(double);void cccc(int i,double d){f_i(i);f_d(d);/* ... */} </span>

 


参考文献:

Bjarne Stroustrup的原文链接地址是 http://www.research.att.com/~bs/bs_faq2.html#callCpp



下面就一个例子,来介绍一下C调用C++的过程:

 

  1. <span style="font-family:Microsoft YaHei;font-size:18px;">// cpp.h 

  2. #ifndef  __cpp_h__ 

  3. #define  __cpp_h__ 

  4. class  class1 {  

  5.     class1();  

  6.     ~class1();  

  7. public:  

  8. int  I;  

  9. int  J;  

  10. int  getI(void);  

  11. };  

  12. #endif 

  13. // end file 

  14. // cpp.cpp 

  15. #i nclude "stdafx.h"

  16. #i nclude  <iostream>  

  17. #i nclude  "cpp.h"

  18. #i nclude  "c.h"

  19. usingnamespace  std;       // 打开标准库名字空间 

  20. class1::class1()  

  21. {}  

  22. class1::~class1()  

  23. {}  

  24. int  class1::getI(void)  

  25. {  

  26. return  I++;  

  27. }  

  28. // 按 C 调用方式编译下面函数 

  29. extern"C"

  30. int  get_class1_I(struct1 * p)  

  31. {  

  32.     class1 * pClass1 = (class1 *)p;  

  33.     cout << "c++: " << pClass1->getI() << endl;  

  34. return  pClass1->getI();  

  35. }  

  36. // end file 

  37. // c.h 

  38. #ifndef  __c_h__ 

  39. #define  __c_h__ 

  40. #ifdef  __cplusplus 

  41. extern"C" {  

  42. #endif 

  43. typedefstruct {  

  44. int  i;             // 与 class1 类中变量一致 

  45. int  j;  

  46.     }struct1;  

  47. #ifdef  __cplusplus 

  48. }  

  49. #endif 

  50. #endif 

  51. // end file 

  52. // c.c 

  53. #i nclude  <cstdio>  

  54. #i nclude  "c.h"

  55. externint  get_class1_I(void * p);  

  56. struct1  s;  

  57. int  main(void)  

  58. {  

  59.     printf ("c: %d\n", get_class1_I(&s));  

  60.     printf ("c: %d\n", get_class1_I(&s));  

  61. return 0;  

  62. }  

  63. // end file</span>

<span style="font-family:Microsoft YaHei;font-size:18px;">// cpp.h#ifndef  __cpp_h__#define  __cpp_h__class  class1 {class1();~class1();public:int  I;int  J;int  getI(void);};#endif// end file// cpp.cpp#i nclude "stdafx.h"#i nclude  <iostream>#i nclude  "cpp.h"#i nclude  "c.h"using namespace  std;       // 打开标准库名字空间class1::class1(){}class1::~class1(){}int  class1::getI(void){return  I++;}// 按 C 调用方式编译下面函数extern "C"int  get_class1_I(struct1 * p){class1 * pClass1 = (class1 *)p;cout << "c++: " << pClass1->getI() << endl;return  pClass1->getI();}// end file// c.h#ifndef  __c_h__#define  __c_h__#ifdef  __cplusplusextern "C" {#endiftypedef struct {int  i;             // 与 class1 类中变量一致int  j;}struct1;#ifdef  __cplusplus}#endif#endif// end file// c.c#i nclude  <cstdio>#i nclude  "c.h"extern  int  get_class1_I(void * p);struct1  s;int  main(void){printf ("c: %d\n", get_class1_I(&s));printf ("c: %d\n", get_class1_I(&s));return 0;}// end file</span>在linux下,执行:

 

gcc -c c.c
g++ -c cpp.cpp
gcc -lstdc++ c.o cpp.o -o result