extern "C"与C++中的C函数调用(1)

  前段时间有人给我发了一篇如何在C中调用C++函数的文章连接,我当时就想,我连如何在C++中调用C都不明白,还谈什么C中调用C++。不过我仍是初略的看了一遍这篇文章,并从中了解到一个颇有用的关键字:extern "C";后来我又查找如何在C++中调用C函数,里面也用到了extern “C”,因此我想要弄明白C和C++的相互调用,那就应该首先弄明白extern “C”。因此我到看了些博文,而后在前人的指引下,进行了一些实验,把实验结果和个人理解记录以下。html

  大多数跟这个有关的博文都有相似以下的一段话,这段话对了解C++有一个很好的前导做用,故而依葫芦画瓢抄录下来:c++

  C++语言之父当初设计该语言的初衷是“a better C”,因此C++通常被认为是C的超集合,可是不要所以而误觉得,“这意味着C++兼容C语言的全部东西”。做为一种欲与C兼容的语言,C++保留了一部分过程式语言的特色(被世人称为“不完全地面向对象”),大部分的C代码能够很轻易地在C++中正确编译,但仍有少数差别,致使某些有效的C代码在C++中没法经过编译。[1]编程

一、深刻探索extern "C"函数

  首先,分析下面的代码片断:post

 1 // Demo.h  
 2 #ifndef SRC_DEMO_H  
 3 #define SRC_DEMO_H  
 4 
 5 #ifdef __cplusplus
 6 extern "C" {
 7 #endif 
 8 /*...*/ 
 9 #ifdef __cplusplus
10 }
11 #endif 
12 
13 #endif  // SRC_DEMO_H 

  显然,头文件中的编译宏“#ifndef SRC_DEMO_H、#define SRC_DEMO_H、#endif”的做用是防止该头文件被重复引用。那么,extern "C"又有什么特殊的做用呢?spa

  下面先深刻探索下extern "C"[2].net

  extern "C" 包含双重含义,从字面上便可获得:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标“C”的。让咱们来详细解读这两重含义。设计

  (1)被extern "C"限定的函数或变量是extern类型的;code

  extern是C/C++语言中代表函数和全局变量做用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量能够在本模块或其它模块中使用。记住,下列语句:htm

  extern int a;

  仅仅是一个变量的声明,其并非在定义变量a,并未为a分配内存空间。变量a在全部模块中做为一种全局变量只能被定义一次,不然会出现链接错误。

  一般,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,若是模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件便可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,可是并不会报错;它会在链接阶段中从模块A编译生成的目标代码中找到此函数。

  与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。所以,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。

  (2)被extern "C"修饰的变量和函数表示其是按照C语言方式编译和链接的;

  C与C++具备不一样的编译和连接方式。C编译器编译函数时不带函数的类型信息,只包含函数符号名字;而C++编译器为了实现函数重载,在编译时会带上函数的类型信息。因此,函数被C++编译后在符号库中的名字与C语言的不一样。例如,假设某个函数的原型为:

  void foo( int x, int y );

  该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不一样的编译器可能生成的名字不一样,可是都采用了相同的机制,生成的新名字称为“mangled name”)。

  _foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。

  一样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,咱们以"."来区分。而本质上,编译器在进行编译时,与函数的处理类似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不一样。

  若是在C++中声明C中定义的函数时,未加extern "C"声明,那么在链接阶段,链接器会从.C文件生成的目标文件中寻找_foo_int_int这样的符号!

  若是加上了extern "C"声明,那么链接器在为C++代码寻找f(2,3)的调用时,寻找的是是未经修改的符号名_foo。

  因此,能够用一句话归纳extern “C”这个声明的真实目的:实现C++与C及其它语言的混合编程。

 

二、extern "C"的使用要点[3]

  (1)能够是单一语句

      extern "C" double sqrt(double);

  (2)能够是复合语句, 至关于复合语句中的声明都加了extern "C"

  extern "C" 
  {
      double sqrt(double);
      int min(int, int);
   }

  (3)能够包含头文件,至关于头文件中的声明都加了extern "C"

  extern "C"
  {   
      #include <cmath>
   }

  (4)不能够将extern "C" 添加在函数内部

  (5)若是函数有多个声明,能够都加extern "C", 也能够只出如今第一次声明中,后面的声明会接受第一个连接指示符的规则。

  (6)除extern "C", 还有extern "FORTRAN" 等。

 

三、参考文献:

[1] 《编写高质量代码:改善C++程序的150个建议》,建议19:明白在C++中如何使用C

[2] 《(转)C++中extern “C”含义深层探索》http://www.cppblog.com/Macaulish/archive/2008/06/17/53689.html

[3] 《c++知识点--extern "C"的做用》http://blog.csdn.net/vinep/article/details/3899780

相关文章
相关标签/搜索