extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。
简单的说,extern “C”是C++声明或定义C语言符号的方法,是为了与C兼容。
加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般只包括函数名。
一个例子:
//moduleA头文件
#ifndef __MODULE_A_H //对于模块A来说,这个宏是为了防止头文件的重复引用
#define __MODULE_A_H
int fun(int, int);
#endif
//moduleA实现文件moduleA.C //模块A的实现部分并没有改变
#include"moduleA"
int fun(int a, int b)
{
return a+b;
}
//moduleB头文件
#idndef __MODULE_B_H //很明显这一部分也是为了防止重复引用
#define __MODULE_B_H
#ifdef __cplusplus //而这一部分就是告诉编译器,如果定义了__cplusplus(即如果是cpp文件, extern "C"{ //因为cpp文件默认定义了该宏),则采用C语言方式进行编译
#include"moduleA.h"
#endif
… //其他代码
#ifdef __cplusplus
}
#endif
#endif
//moduleB实现文件 moduleB.cpp //B模块的实现也没有改变,只是头文件的设计变化了
#include"moduleB.h"
int main()
{
cout<<fun(2,3)<<endl;
}
(1)extern
extern是编程语言中的一种属性,它表征了变量、函数等类型的作用域(可见性)属性,是编程语言中的关键字。当进行编译时,该关键字告诉编译器它所声明的函数和变量已在其他文件中定义,可以在本模块或者文件以及其他模块或文件中使用。
通常,程序员会在 "*.c" 文件中声明定义变量或定义函数,并在“*.h”(头文件)中使用该关键字限定变量或函数等,然后可在该头文件或其他模块中include使用,如:
file1.c
1 2 |
|
file1.h
1 2 |
|
file2.c
1 2 3 4 5 6 7 8 |
|
(2)“C”
编程语言种类繁多各有优劣,因此在做软件工程时,往往会出现不同语言嵌套或互相调用的情况,例如在C和C++之间就经常出现互相调用。虽然C++是C的超集,但是,它们之间的编译器是不同的,这就产生了各自的编译器在对C和C++进行编译时要依据哪一个作为大家都认可的规范或者约定的问题。很幸运的是,通过一些基础特征我们制定了这样的一个规约,这就是“C”的出处,这些基础特征就是:
1)这种调用编译是一种“超”链接;
2)这种调用编译不能影响现有的编译规范;
3)C++是C的拓展,是C的升华。
根据1),extern关键字可以表达这种“超”链接;
根据2)、3)用“C”来规约在C++中对C的编译。
因此,extern "C"表明了一种编译规约,其中extern是关键字属性,“C”表征了编译器链接规范。对于extern "C"可以理解成在C++/C中的混合编程的编译指令。
明白了这层意思,下面的代码就不难解释了:
1 2 3 4 5 6 7 8 9 10 11 |
|
Qt Creator运行:
extern "C"的惯用法
(1)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理:
1 2 3 4 5 |
|
而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。
例如C函数例子工程中包含的三个文件的源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern "C" { }。
(2)在C中引用C++语言中的函数和变量时,C++的头文件需添加extern "C",但是在C语言中不能直接引用声明了extern "C"的该头文件,只需要在C源文件中将C++中定义的extern "C"函数声明为extern类型。
笔者编写的C引用C++函数例子工程中包含的三个文件的源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
总结
C和C++对函数的处理方式是不同的.extern "C"是使C++能够调用C写的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话,那么就要使用extern "C"来说明。
时常在cpp的代码之中看到这样的代码:
1 2 3 4 5 6 7 8 |
|
这样的代码到底是什么意思呢?首先,__cplusplus是cpp中的自定义宏,那么定义了这个宏的话表示这是一段cpp的代码,也就是说,上面的代码的含义是:如果这是一段cpp的代码,那么加入extern "C"{和}处理其中的代码。
要明白为何使用extern "C",还得从cpp中对函数的重载处理开始说起。在c++中,为了支持重载机制,在编译生成的汇编码中,要对函数的名字进行一些处理,加入比如函数的返回类型等等.而在C中,只是简单的函数名字而已,不会加入其他的信息.也就是说:C++和C对产生的函数名字的处理是不一样的.
因此,为了在C++代码中调用用C写成的库文件,就需要用extern "C"来告诉编译器:这是一个用C写成的库文件,请用C的方式来链接它们。
比如,我们有了一个C库文件,它的头文件是f.h,产生的lib文件是f.lib,那么我们如果要在C++中使用这个库文件,我们需要这样写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
重新编译并且链接就可以过去了.
总结
C和C++对函数的处理方式是不同的.extern "C"是使C++能够调用C写作的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话,那么就要使用extern "C"来说明。