在阅读代码的时候经常遇见extern关键字,由于平时接触很少一般没用到所以不是很熟,这里特别学习一下。
首先得熟悉C++中声明与定义的概念。
变量的定义用于为变量分配存储空间,还可以为变量指定初始值,在一个程序中变量有且仅有一个定义。
变量的声明用于向程序表面变量的类型和名字。
定义也是声明:当定义变量时我们声明了它的类型和名字,这时可以用extern关键字声明变量名而不定义它
extern int i; //声明但是不定义i int i; //声明且定义i
extern声明不是定义也不分配存储空间,它只是说明变量定义在程序的其他地方,程序中变量可以声明多次,但只能定义一次。
extern double pi = 3.14; //定义 double pi; //错误!重复定义
extern double pi = 3.14; //定义 extern double pi; //正确!可重复声明 extern double pi = 3.14; //错误!重复定义
变量定义在程序的其他地方也就代表了可以在其他.cpp文件中定义,只需要进行extern声明就可以使用。比如有2个.cpp文件:test1.cpp test2.cpp,在test1.cpp中定义int i = 0;在test2.cpp中只需要加上extern int i;就可以使用test1.cpp中的i。但同时,如果在相同作用域内在定义int i;就会出现重复定义错误比如:
// test1.cpp int i = 0; // test2.cpp extern int i; int i = 1; //报错,重复定义
因此需要重新定义一个int类型变量i可以定义为局部变量
// test1.cpp int i = 0; // test2.cpp #include <iostream> extern int i; int main() { int i = 1; std::cout << i << std::endl; system("pause"); return 0; }
此时输出结果为1
函数以及类的声明和定义也一样可以用extern来声明在外部定义,其实这么做有什么好处呢?比如在a.h定义了全局变量int i = 0;若a1.cpp和a2.cpp中同时include "a.h"则编译不成功,因为i重复定义。这时就会出现非常常见的这种报错fatal error LNK1169: 找到一个或多个多重定义的符号。解决方式如下:
// a.h int i = 0; // a1.cpp #include "a.h" // a2.cpp extern int i;
也就是如果有一个.cpp文件包含了.h文件,那么相当于该cpp文件里定义了int i;那么在其他文件中要使用这个全局变量就只需要使用extern int i;进行外部声明即可。注意,如果去掉了包含a.h的a1.cpp,那么编译失败,因为找不到i的定义,因为.h文件并不能单个编译。所以实际编程的时候.h和.cpp都是成对出现,往往包含了一个类的声明和定义。也避免去寻找是否有.cpp文件包含了该.h文件。
其实在C和C++混合编程的时候,extern更多的是用在C++里调用C函数。
在C++里,为了实现函数重载,你定义两个函数void fun(int); void fun(double);在调用它时其实相当于定义了两个函数void fun_int(int); void fun_double(int);当然这里只是举例,实际情况不知道改成了什么名字,但肯定不是fun本身。而C语言没有重载的特性,在.cpp中调用.c中的fun()就会因为无法识别函数名出错。
为了使用C语言定义的函数通常使用以下语法
extern "C"
{
// C语言定义的变量和函数
}
// a1.c #include <stdio.h> void fun(int i) { printf("%d\n", i); } // a2.cpp #include <iostream> extern "C" { void fun(int); } int main() { fun(1); system("pause"); return 0; }
以上代码如果在a2.cpp中直接extern void fun(int);再运行会报错a2.obj : error LNK2019: 无法解析的外部符号 "void __cdecl fun(int)" ([email protected]@[email protected]),该符号在函数 _main 中被引用。[email protected]@[email protected]就是编译器自动扩展的函数名了。
如果C函数是在头文件中定义只需 extern "C" { #include "a.h" }即可,a.h为.c文件包含的头文件。
而在C语言中调用C++的函数,那么在.cpp中为要在.c中调用的函数名前加上extern "C"即可,示例如下
// a2.cpp #include <iostream> extern "C" { void fun(int); void fun2(double); }; void fun(int i) { printf("%d\n", i); } void fun2(double x) { printf("%lf\n", x); } // a1.c #include <stdio.h> extern void fun(int); extern void fun2(double); int main() { fun(1); fun2(1.2); return 0; }
输出结果为
1
1.200000
C/C++ extern关键字