extern "C"

来源:互联网 发布:知否18年什么时候播出 编辑:程序博客网 时间:2024/05/04 00:01
函数被C++编译后在符号库中的名字与C语言的不同。
例如,假设某个函数的原型为:

  void foo( int x, int y );

该函数被C编译器编译后在符号库中的名字为_foo,

而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangledname”)。

_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。

例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y)编译生成的符号是不相同的,后者为_foo_int_float。

  同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。
--------------------------------------------------------------------------------------------------------------------------
未加extern "C"声明时的连接方式
假设在C++中,模块A的头文件如下:
  // 模块A头文件 moduleA.h

  #ifndef MODULE_A_H

  #define MODULE_A_H

  int foo( int x, int y );

  #endif

在模块B中引用该函数:

  // 模块B实现文件 moduleB.cpp

  #include "moduleA.h"

  foo(2,3);

实际上,在连接阶段,连接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号!

  加extern "C"声明后的编译和连接方式

  加extern "C"声明后,模块A的头文件变为:

  // 模块A头文件 moduleA.h

  #ifndef MODULE_A_H

  #define MODULE_A_H

  extern "C" int foo( int x, int y );

  #endif

  在模块B的实现文件中仍然调用foo( 2,3 ),其结果是:
  (1)模块A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式;
  (2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是经过经修改的符号名_foo_int_int
  如果在模块A中函数声明了foo为extern "C"类型,而模块B中包含的是extern int foo( int x, int y ) ,则模块B找不到模块A中的函数;反之亦然。

  ------------------------------------------------------------------------------------------------------------------------------

一句话:加入extern “C”,编译器会按照c的规则处理函数或者变量。

              不加extern “C",编译器会按照c++的规则处理函数或者变量。

原创粉丝点击