在实际开发C++项目的时候,一个项目里面往往会包含多个cpp文件,多个头文件,有时还会有c文件。由于变量的声明可以有多次,但定义只能有一次,这就不可避免地要使用extern,static关键字。弄清楚这几个关键字之间的用法和区别,能节省很多调试项目的时间,尤其是对于一些难以定位的链接错误。下面分别介绍:
一、extern关键字
这个关键字可能是最容易用错的一个,一方面可能是因为平时写的小程序不太会用到这个关键字,另一方则是这个关键字确实有些不太容易理解的用法。
extern关键字主要有两个作用:1、声明一个全局变量;2、extern “C” { /*用C实现的内容(通常写在另外的.c文件中)*/ }
1、当用extern声明一个全局变量的时候,首先应明确一点:extern的作用范围是整个工程,也就是说当我们在.h文件中写了extern int a;编译的时候编译器会去其他的.cpp文件中找有没有int a的定义,如果没有,编译报错;当extern int a;写在.cpp文件中时,编译器会在这个.cpp文件该声明语句之后找有没有int a的定义,然后去其他的.cpp文件中找,如果都找不到,编译报错。另外值得注意的一点是,当extern语句出现在头文件中时,不要将声明和定义在一条语句中给出,也就是不要在头文件中写类似于这样的语句:
extern int a = 1;
这样做的一个可能的原因是:担心在其他的.cpp文件中忘记给出该变量的定义,所以干脆就在声明的时候直接给出定义得了,什么编译的时候报错说变量a没有定义。
对变量没有定义的忧虑是应该提倡的,但解决这种忧虑的办法却弄巧成拙了。前面已经说了,extern声明全局变量的作用范围是整个工程,如果我们在头文件中给出全局变量的定义,如果工程中有多个.cpp文件包含了此头文件,则这个全局变量在工程中定义了多次,因此编译报错。遵照的法则其实很简单:只在头文件中通过extern给出全局变量的声明,在.cpp文件中用到该变量时才给出定义(并且只能定义一次)。
2、C++完全兼容C,当extern与“C”连用时,作用是告诉编译器用C的编译规则去解析extern “C”后面的内容。最常见的差别就是C++支持函数重载,而标准C是不支持的。如果不指明extern “C”,C++编译器会根据自己的规则在编译函数时为函数名加上特定的后缀以区别不同的重载版本,而如果是按C的标准来编译的话,则不需要。
二、static关键字
static关键字的作用有很多,声明静态全局变量,类的静态成员等。这里主要讨论他在修饰全局变量时与extern的区别。有两点需要注意:
1、static修饰全局变量时,声明和定义是同时给出的;2、static的全局作用域只是自身编译单元。
一个编译单元指一个.cpp文件和他所包含的头文件。也就是说static在修饰全局变量时,“全局”的范围是小于extern的。因此,在头文件中用static声明(和定义)全局变量,是不会出现上面讨论的重复定义的问题的。