C++中extern "C"的用法

本文参考了以下两篇文章:

1. http://songpengfei.iteye.com/blog/1100239 (主要讲了C++中引用C库)

2. http://www.cnblogs.com/rollenholt/archive/2012/03/20/2409046.html

       比如说你用C 开发了一个DLL 库,为了能够让C ++语言也能够调用你的DLL 输出(Export) 的函数,你需要用extern "C" 来强制编译器不要修改你的函数名。通常,在C 语言的头文件中经常可以看到类似下面这种形式的代码:

#ifdef __cplusplus  
extern "C" {  
#endif  
  
/**** some declaration or so *****/  
  
#ifdef __cplusplus  
}  
#endif  

        那么,这种写法什么用呢?实际上,这是为了让CPP 能够与C 接口而采用的一种语法形式。之所以采用这种方式,是因为两种语言之间的一些差异所导致的。由于CPP 支持重载,也就是具有相同函数名的函数可以完成不同的功能,CPP 通常是通过参数区分具体调用的是哪一个函数。在编译的时候,CPP 编译器会将参数类型和函数名连接在一起,于是在程序编译成为目标文件以后,CPP 编译器可以直接根据目标文件中的符号名将多个目标文件连接成一个目标文件或者可执行文件。但是在C 语言中,由于完全没有重载的概念,C 编译器在编译时除了会在函数名前面添加一个下划线之外,什么也不会做(至少很多编译器都是这样干的)。由于这种的原因,当采用CPP 与C混合编程的时候,就可能会出问题。

         假设在某一个头文件中定义了这样一个函数: 

      int foo(int a, int b);

而这个函数的实现位于一个.c 文件中,同时,在.cpp 文件中调用了这个函数(通过引用.h文件包含,lib库链接)。那么,当CPP 编译器编译这个函数的时候,就会把这个函数名改成_fooii ,这里的ii 表示函数的第一参数和第二参数都是整型。而C 编译器却有将这个函数名编译成_foo 。也就是说,在CPP 编译器得到的目标文件中,foo() 函数是由_fooii 符号来引用的,而在C 编译器生成的目标文件中,foo() 函数是由_foo 指代的。但链接器工作的时候,它可不管上层采用的是什么语言,它只认目标文件中的符号。于是,链接器将会发现在.cpp 中调用了foo() 函数,但是在其它的目标文件中却找不到_fooii 这个符号,于是提示链接过程出错。extern "C" {} 这种语法形式就是用来解决这个问题的。本文将以示例对这个问题进行说明。

        采用extern "C" {} 这种形式的声明,可以使得CPP 与C 之间的接口具有互通性,不会由于语言内部的机制导致连接目标文件的时候出现错误。

        注意:用g++编译cpp程序时,编译器会定义宏 __cplusplus ,可根据__cplusplus是否定义决定是否需要extern "C"。

        一、所以,在使用C++调用C库的时候,可以通过使用下面几种方法实现兼容:

        1. 现在要写一个c语言的模块,供以后使用(以后的项目可能是c的也可能是c++的),源文件事先编译好,编译成.so或.o都无所谓。头文件中声明函数时要用条件编译包含起来,如下:       

#ifdef __cpluscplus
extern "C" {
#endif

//some code

#ifdef __cplusplus
}
#endif
       2. 如果这个模块已经存在了,可能是公司里的前辈写的,反正就是已经存在了,模块的.h文件中没有extern "C"关键字,这个模块又不希望被改动的情况下,可以这样,在你的c++文件中,包含该模块的头文件时加上extern "C", 如下:     

extern "C" {
#include "test_extern_c.h"
}
       3. 上面例子中,如果仅仅使用模块中的1个函数,而不需要include整个模块时,可以不include头文件,而单独声明该函数,像这样:       

extern "C" {
int ThisIsTest(int, int);
}

     二、在C中引用C++语言中的函数和变量时,C++的头文件需添加extern "C",但是在C语言中不能直接引用声明了extern "C"的该头文件,应该仅将C文件中将C++中定义的extern "C"函数声明为extern类型。

       c++头文件:   cppExample.h  

#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add( int x, int y );
#endif
       C++源文件:cppExample.cpp
#include "cppExample.h"
int add( int x, int y )
{
    return x + y;
}
      C实现文件 cFile.c     
/* 这样会编译出错:#include "cExample.h" */
extern int add( int x, int y );
int main( int argc, char* argv[] )
{
    add( 2, 3 );
    return 0;
}
如果深入理解了第3节中所阐述的extern "C"在编译和连接阶段发挥的作用,就能真正理解本节所阐述的从C++引用C函数和C引用C++函数的惯用法

你可能感兴趣的:(C++中extern "C"的用法)