原文链接:http://ju.outofmemory.cn/entry/209478
全局变量( 全程变量 ):与局部变量不同,全局变量在整个程序都是可见的,可在整个程序运行过程中,对于任何一个程序都是可用的。全局变量的说明的位置在所有函数之外,会自动初始化,可被任何一个函数使用,读取或者写入。(多个文件中可以声明同名的全局变量,但是只能被定义一次,即只有一个文件对该全局变量定义了)
局部变量:局部变量是指在函数内部说明的变量(有时也称为自动变量),用关键字auto进行说明。 所有的非全局变量都被认为是局部变量,所以auto实际上从来不用。局部变量在函数调用时自动产生,但 不会 自动初始化(与不同的编译器有关,有的编译器会初始化为 0 ), 随函数调用的结束,这个变量也就自动消失了,下次调用此函数时再自动产生,还要重新赋值,退出时又自动消失。
例:
int a; // 全局变量,若没有初始化则自动初始化为0
int fun(){
int b; // 局部变量,作用域为单个函数, 不会自动初始化
b=0;
}
静态变量:用关键字static声明。根据变量的类型可以分为静态局部变量和静态全局变量。
(1)静态局部变量
它与局部变量的区别在于:在函数退出时,这个变量始终存在,但不能被其它函数使用,当再次进入该函数时,将保存上次的结果, 并且静态局部变量 只初始化一次 ,若未被显示初始化则自动初始化为0,。其它与局部变量一样。
例:
int main(){
int i;
for(i=0;i<5;i++){
fun1();
}
for(i=0;i<5;i++){
fun2();
}
}
int fun1(){
static int i=3;
printf("%d ", i++);
}
int fun2(){
static int i;
i=3;
printf("%d ", i++);
}
输出结果: 3 4 5 6 7 3 3 3 3 3
(只初始化一次,并且函数退出时变量仍然存在,同时表示了初始化与赋值不同)
(2)静态全局变量
静态全局变量就是指只在定义它的源文件中可见而在其它源文件中不可见的变量。
它与全局变量的区别是:全局变量可以再说明为外部变量( extern ),被其它源文件使用,而静态全局变量却不能再被说明为外部的,即只能被所在的源文件使用。(static 可用来降低耦合,将不必要对外的变量保护起来)
外部变量:外部变量用关键字extern声明。为了使变量除了在定义它的源文件中可以使用外,还可以被其它文件使用,就要将全局变量通知每一个程序模块文件,此时可用 extern来说明。
(如在文件a中定义了 int i=1; 在文件b中使用i 则需要使用 extern声明,extern int i; extern声明时不可赋值,如果在b中使用 int i=1; 重复定义i 则报错)
寄存器变量:通常在比较注重在执行速度的情况下使用。其思想是告诉编译器把该变量放在某个CPU寄存器中,但编译器可以 忽略 此选项。因为数据在寄存器中操作比在内存中快,这样就提高了程序代码的执行速度。寄存器变量的说明是在变量名及类型之前加上关键字register。过量的寄存器声明并没有什么害处,因为编译器可以忽略过量的或不支持的寄存器变量声明。值得注意的是无论寄存器变量实际上是否放在寄存器中,它的地址都是不能访问的,取地址运算符&不能作用于寄存器变量。只有 整型和字符型变量 可定义为寄存器变量,register声明只适用于 局部变量 或函数的 形式参数 , register int i;
volatile 变量:volatile 影响编译器编译的结果,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错。
例如:
volatile int i=10;
int j = i;
...
int k = i;
volatile 告诉编译器 i 是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问,不会出错。
解析static关键字:static在c里面可以用来修饰变量,也可以用来修饰函数。先看用来修饰变量的时候。变量在c里面可分为存在全局数据区、栈和堆里。其实我们平时所说的堆栈是栈而不包含堆,不要弄混。
int a ;
main(){
int b ;
int c* = (int *)malloc(sizeof(int));
}
a是全局变量,b是栈变量,c是堆变量。
static对全局变量的修饰,可以认为是限制了只能是本文件引用此变量。有的程序是由好多.c文件构成。彼此可以互相引用变量,但加入static修饰之后,只能被本文件中函数引用此变量。static对栈变量的修饰,可以认为栈变量的生命周期延长到程序执行结束时。一般来说,栈变量的生命周期由OS管理,在退栈的过程中,栈变量的生命也就 结束了。但加入static修饰之后,变量已经 不在存储在栈中,而是和全局变量一起存储 。同时,离开定义它的函数后不能使用,但如再次调用定义它的函数 时,它又可继续使用, 而且保存了前次被调用后留下的值。
static对函数的修饰与对全局变量的修饰相似,只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。静态函数会被自动分配在一个一直使用的存储区,直到退出应用程序实例,避免了调用函数时压栈出栈,速度快很多。