首页 > 代码库 > C++ static 、extern以及全局变量之间的相关逻辑

C++ static 、extern以及全局变量之间的相关逻辑

全局变量,就是指那些定义在函数之外的变量,当然也是定义在类之外的变量。


(1)全局变量会被自动初始化,函数中的变量不会被自动初始化,类中定义的那些成员变量(内建)也不会自动初始化。那么这里有一个疑问,为什么要这样设置?并且为什么,在进程内存区中,分为初始化了的全局变量、静态变量,和未初始化的全局、静态变量。

(2)全局变量如果加上static关键字,事情将会变得很奇妙。


我们知道,全局变量理论上是指应用程序级别的全局。普通的全局变量是面向整个程序的,当各个文件各自编译,然后链接成一个可执行程序之后,全局变量的确是被所有文件中的“看到的”。
如何想让别的文件在编辑程序的时候就能够看到?
第一个就是#include方法,但是这个方法,其实是将文件合并成一个文件,并没有正面回答。
第二个就是在要使用该变量的文件中声明(extern)一个外部变量,这样等于就是告诉编译器,“该变量是有的,只是在另外一个文件中,等到链接的时候你就可以看到了。”这个extern必须要加,否则就是重新定义个变量,到时候连接会出现重定义问题。

但是,如果你在全局变量前加上static,那么它的作用范围就变小了,编程了文件范围。这就会导致该变量是不容许别的文件通过extern声明方式来操作。因为该变量对其它文件是不可见的。


我们所说的变量的生命周期和作用域时我们有这样的说法:
1) 全局变量和静态变量的生命周期为整个进程,他们都处在内存的同一个区域
2) 普通全局变量的作用域为全局(整个软件,可跨域文件,其他文件想使用可以使用extern声明),函数中的静态变量的作用域为该函数

3) 静态全局变量的作用域则被限制在该文件中。所以,这个时候其他文件通过extern想使用该文件是不行的,就算成功啦,那是因为你引用了其他文件中的定义。同时,由于作用域被限制在当前文件,所以,不同的文件定义自己的全局变量就不会担心与其他文件出现冲突。


所以,这里就有一个有关全局变量定义的标准了。
1) 如果你在这个文件中定义的全局变量不打算给别人用,那么你就将它定义为static全局变量吧!因为这样你不必担心其他文件也定义了一个同名变量,在连接的时候出现重定义。
2) 如果你的全局变量是打算给其他文件使用的,那么就不要加上static,因为这样在其他文件中可以使用extern对该定义进行引用。

3) 这么说来,static 和extern是不能同时用来修饰一个变量的。extern修饰表示该变量只是声明,声明它使用了其他文件的变量定义,static的修饰表示我这个变量(自己定义的),只能被当前文件访问。两者完全冲突,所以编译器会报错——‘n’的声明中有相互冲突的限定符。


Extern有两种用法:
(1)与C一起使用 extern C ,来在C++中表达在编译的时候按照C的风格进行编译。

(2)修饰普通全局变量的声明,(extern  int n;)注意它只能是声明,不能定义初始化,它声明表示,该变量可以从另外一个文件中找到,现在大胆使用就行了。到时候(链接的时候)就可以找到了,所以我认为这个extern关键是来支持,当前文件可以通过编译器的检查。当前文件使用了另外一个文件内定义的东西,但是又不能直接#include它,所以导致这种技术的出现。注意,必须有一个文件定义了该变量(int n;)如果没有一个文件定义了它,那么编译的时候能够通过,但是在连接的时候,文件找不到你给它的承诺,所以就会报错——undefined reference to `n‘。


Static的应用场景:
(1)在C++面向对象中修饰成员函数或变量,这表明它所属范围为这个类,而不是对象。
(2)在局部变量中(函数中)修饰变量,表示该变量是这个函数范围内的不变的,而不是随着每一次的函数调用而更新。所以你会发现,static修饰函数中的变量和修饰类中的成员有异曲同工之妙。函数每次被调用,类似于类每次被实例化。普通的成员都会是一个新的,而static成员与至始至终属于该函数(类)。
(3)在全局变量中修饰变量,表示该变量的作用范围为当前文件,而不是整个程序。

C++ static 、extern以及全局变量之间的相关逻辑