一、生存区
不少人对于生存期有着一种错误的理解,认为变量离开了它的作用域,其生存期就结束了。产生这种误解的原因,是对于生存期的概念理解不深刻。所谓的生存期,其实是指变量占用内存或者寄存器的时长。根据变量存储类别的不同,在编译的时候,变量将被存放到动态存储区或静态存储区中,所以其生存期是由声明时的存储类别所决定的。
(1)首先我们讲一下静态存储区与动态存储区
静态存储区:
存放全局变量和静态变量,在程序执行之前分配存储空间,占据固定的内存单元。
动态存储区:
(2)存储类别和相应的变量存放的是函数里面的局部变量、函数的返回值、形式参数等,它在函数被执行的过程中自动进行动态分类,在执行完成该函数之后自动释放。由于这种分配和释放都是每次执行到函数时候进行的,因此前后两次同一个函数,其临时变量分配到的地址可能是不同的。
①自动(auto)
非静态变量的局部变量即为自动变量,其类型说明符为auto, 在C 语言中,将函数内没有存储类别说明的变量均视为自动变量,即自动变量可以省去说明符auto。如:
void print()
{int a;
(二)作用域}
等价于
void print()
{
auto int a;
}
②寄存器(register)
指定了register 存储类别的变量即为寄存器变量。使用寄存器变量是为了提高执行效率,因为频繁地从内存单元存取变量相比于从寄存器中存取变量需要消耗更多的时间,所以使用register 声明的寄存器类型的变量存放在寄存器中,不会占用内存单元,可以提高程序的执行效率。值得注意的一点是,只有局部变量才可以定义成寄存器变量。为了加深读者的印象,我们通过下面两段代码来对比不使用register 和使用register 的程序执行效率。
不用register 的程序如下:
不用register 的程序的运行结果:int main(int argc, char * argv[]) { struct timeval start,end; gettimeofday( &start, NULL ); /* 测试起始时间*/ double timeuse; double sum; int j,k; for(j=0;j<1000000000;j++) for(k=0;k<10;k++) sum=sum+1.0; gettimeofday( &end, NULL ); /* 测试终止时间*/ timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec ; timeuse /= 1000000; printf(" 运行时间为:%f\n",timeuse); return 0; }
root@ubuntu:/home# ./ce
运行时间为:35.608037
用register 的程序如下:#include <stdio.h> #include <sys/time.h> int main(int argc, char * argv[]) { struct timeval start,end; gettimeofday( &start, NULL ); /* 测试起始时间*/ double timeuse; register double sum; register int j,k; for(j=0;j<1000000000;j++) for(k=0;k<10;k++) sum=sum+1.0; gettimeofday( &end, NULL ); /* 测试终止时间*/ timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec ; timeuse /= 1000000; printf(" 运行时间为:%f\n",timeuse); return 0; }
用register 的程序的运行结果:
root@ubuntu:/home# ./ce
运行时间为:9.678347
对比上面的两个运行结果,我们发现,使用了register 的程序执行速度提高了近3 倍,但是读者要注意,虽然可以使用register 来提高程序的执行速度,但是也不能大量使用register,因为寄存器的数目是有限的。
③静态(static)
关于静态变量,值得注意的一点是,它的生存期是从程序开始运行到程序运行结束。静态变量不属于动态存储,是静态存储。静态局部变量的生存期虽然是从程序开始运行到程序运行结束,但是它的作用域并不会因此而改变,而且仍然与其作为自动变量的作用域相同。静态全局变量的特点是,它只能在被定义的源程序文件中使用,即它只能被本源程序文件的函数调用,而不能被其他的源程序文件中的函数调用。静态局部变量和静态全局变量的定义形式都是在数据类型前加上一个静态存储定义符static。但是值得注意的是,两者的初始化方式不同,静态局部变量在它所在的函数被执行时初始化,之后再次执行该函数时,该静态局部变量不再进行初始化,其中保留的是上一次的运行结果;而静态全局变量的初始化是在执行main() 函数之前完成的,其静态全局变量的当前值由最近一次对它的赋值操作决定。在此,我们重点来看看静态局部变量的使用。
运行结果:#include <stdio.h> void print(void) { static int a=0; printf(" 静态局部变量a=%d\n", a++); } int main(void) { print(); print(); return 0; }
静态局部变量a=0
静态局部变量a=1
分析运行结果可以得知,静态局部变量在初始化以后,再次执行该函数时静态局部变量保存的是上一次的运行结果。
④外部(extern)
外部存储类别定义方式为在全局变量类型前面加上关键字extern,如果没有指定全局变量的存储类别,则默认为extern。
不少人在编程中并不重视作用域的问题,实际上,它是C 语言程序设计中的一个要点。通常来说,一段程序代码中所用到的名字并不总是有效或可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。