全局变量,就是指那些定义在函数或类之外的变量,它可作为多个类或函数都需要共同使用的变量。
(1)全局变量会被自动初始化,函数中的变量不会被自动初始化,类中定义的那些成员变量(内建)也不会自动初始化。那么这里有一个疑问,为什么要这样设置?并且为什么,进程内存区中,分为初始化了的全局变量和静态变量,和未初始化的全局和静态变量。
(2)全局变量如果加上static关键字,事情将会变得很奇妙。
我们知道,全局变量理论上是指应用程序级别的全局。普通的全局变量是面向整个程序的,当各个文件各自编译,然后链接成一个可执行程序之后,全局变量的确是被所有文件中的“看到的”,但是,如果想让别的文件在编译程序的时候就能够看到,(如果你不做然后措施,直接使用另外一个文件中定义的变量,那将通不过编译)
有两个办法:
第一个就是#include方法,但是这个方法,其实是将文件合并成一个文件,并没有正面回答。
第二个就是在要使用该变量的文件中声明(extern)一个外部变量,这样等于就是告诉编译器,“该变量是有的,只是在另外一个文件中,等到链接的时候你就可以看到了。”这个extern必须要加,否则就是重新定义个变量,到时候连接会出现重定义问题。
但是,如果你在全局变量前加上static,那么它的作用范围就变小了,编程了文件范围。这就会导致该变量是不容许别的文件通过extern声明方式来操作。因为该变量对其它文件是不可见的。
我们所说的变量的生命周期和作用域时我们有这样的说法:
1) 全局变量和静态变量的生命周期为整个进程,他们都处在内存的同一个区域
2) 普通全局变量的作用域为全局(整个软件,可跨域文件,其他文件想使用可以使用extern声明),函数中的静态变量的作用域为该函数。
3) 静态全局变量,的作用域则被限制在该文件中,所以,这个时候其他文件通过extern想使用该文件是不行的,(就算成功啦,那是因为你引用了其他文件中的定义)。同时,由于作用域被限制在当前文件,所以,不同的文件定义自己的全局变量就不会担心与其他文件出现冲突。
一直以来,有一个有关全局变量定义的标准:
1) 如果在这个文件中定义的全局变量不打算给别人用,那么你就将它定义为static全局变量吧!因为这样你不必担心其他文件也定义了一个同名变量,在连接的时候出现重定义。
2) 如果你的全局变量是打算给其他文件使用的,那么就不要加上static,因为这样在其他文件中可以使用extern对该定义进行引用。
3) 这么说来,static 和extern是不能同时用来修饰一个变量的,extern修饰表示该变量只是声明,声明它使用了其他文件的变量定义,static的修饰表示我这个变量(自己定义的),只能被当前文件访问。两者完全冲突,所以编译器会报错——‘n’的声明中有相互冲突的限定符。
函数或变量在声明时,并没有给它实际的物理内存空间,它有时候可以保证你的程序编译通过, 但是当函数或变量定义的时候,它就在内存中有了实际的物理空间,如果你在编译模块中引用的外部变量没有在整个工程中任何一个地方定义的话, 那么即使它在编译时可以通过,在连接时也会报错,因为程序在内存中找不到这个变量!你也可以这样理解, 对同一个变量或函数的声明可以有多次,而定义只能有一次!
在IDE开发工具大行其道的今天,对于编译的一些概念很多人已经不再清楚了,很多程序员最怕的就是处理连接错误(LINK ERROR), 因为它不像编译错误那样可以给出你程序错误的具体位置,你常常对这种错误感到懊恼,但是如果你经常使用gcc,makefile等工具在linux或者嵌 入式下做开发工作的话,那么你可能非常的理解编译与连接的区别!当在VC这样的开发工具上编写完代码,点击编译按钮准备生成exe文件时,VC其实做了两 步工作,第一步,将每个.cpp(.c)和相应.h文件编译成obj文件;第二步,将工程中所有的obj文件进行LINK生成最终的.exe文件,那么错 误就有可能在两个地方产生,一个是编译时的错误,这个主要是语法错误,另一个是连接错误,主要是重复定义变量等。我们所说的编译单元就是指在编译阶段生成 的每个obj文件,一个obj文件就是一个编译单元,也就是说一个cpp(.c)和它相应的.h文件共同组成了一个编译单元,一个工程由很多个编译单元组 成,每个obj文件里包含了变量存储的相对地址等 。