(参考:http://blog.csdn.net/daydreamingboy/article/details/8775409)

    作为C++入门学者,看了几篇关于extern “C”的文章,发现没有解决自己的疑惑,找到上边的博文,然后明白了extern “C”的使用。借用文中的话说,好记性不如烂笔头,为了理顺一下自己的思路,我也简单总结一下,希望日后便于理解。

首先,确定一下extern “C”的基本含义及意义。

    基本含义:1、首先,被它修饰的目标是"extern"的,即被extern "C"限定的函数或变量是extern类型的(extern是C/C++语言中表明函数和全局变量的作用范围的关键字,该关键字告诉编译器,其申明的函数和变量可以在本模块或其他模块中使用)。

                  2、其次,被它修饰的目标代码是"C"的。

    意义:实现C++代码能够正确调用C语言代码。

 

其次,了解C++编译器和C编译器对代码编译的不同之处。

    C函数名和C++函数名采用不同的命名规则。

    由于C、C++编译器对函数的编译处理是不完全相同的,尤其对于C++来说,支持函数的重载,编译后的函数一般是以函数名和形参类型来命名的。

    例如函数void fun(int, int),编译后的可能是(不同编译器结果不同)_fun_int_int(不同编译器可能不同,但都采用了类似的机制,用函数名和参数类型来命名编译后的函数名);而C语言没有类似的重载机制,一般是利用函数名来指明编译后的函数名的,对应上面的函数可能会是_fun这样的名字。

    因此,两者产生的不同代码,会使得链接器链接时产生错误。

 

最后,明白如何产生链接错误。

    用C语言代码写的函数,编译后会生成_fun这样的名字,而该文件是作为调用文件或者说是以头文件的形式包含在.cpp文件中的,这部分内容不再改变。

    而.CPP文件需要调用上边的函数,于是需要在.cpp文件中声明C编写的函数或者头文件。当在该.cpp中不包含extern “C”时,被调用的.C文件会以C++编译器规则将函数void fun(int, int)编译为_fun_int_int,然后再用编译后的_fun_int_int名字去调用匹配.C文件中的_fun,显然,链接错误。但是,如果在该.cpp中包含了extern “C”时,这时候被调用的.C文件会以C编译器规则将函数void fun(int, int)编译为_fun,然后再用编译后的_fun名字去调用匹配.C文件中的_fun,显然,链接成功。

(这里啰嗦一点的目的是让大家明白,被调用的.C文件是不变的,加extern “C”修饰的是在调用者.CPP文件中。)

 

补充,实现.C和.CPP文件的自动调用

    (参考:http://www.jb51.net/article/62351.htm)

    很多时候我们写一个头文件声明了一些C语言的函数,而这些函数可能被C和C++代码调用,当我们提供给C++代码调用时,需要在头文件里加extern “C”,否则C++编译的时候会找不到符号,而给C代码调用时又不能加extern “C”,因为C是不支持这样的语法的,常见的处理方式是这样的,我们以C的库函数memset为例:

    #ifdef __cplusplus
    extern "C" { void *memset(void*, int, size_t); }
    #endif

    #ifndef __cplusplus
    void *memset(void*, int, size_t);
    #endif  

    其中__cplusplus是C++编译器定义的一个宏,如果这份代码和C++一起编译,那么memset会在extern "C"里被声明,如果是和C代码一起编译则直接声明,由于__cplusplus没有被定义,所以也不会有语法错误。这样的技巧在系统头文件里经常被用到。

 

    只是进行了简单总结,描述了一个大体思路,有很多细节没有补充,不足之处请多多指教。