作用域和链接描述了标识符的可见性。存储期描述了通过这些标识符访问的对象的生存期。C对象有4种存储期:静态存储期、线程存储期、自动存储期、动态分配存储期。
如果对象具有静态存储期,那么它在程序的执行期间一直存在。文件作用域变量具有静态存储期。注意,对于文件作用域变量,关键字static表明了其链接属性,而非存储期。以static声明的文件作用域变量具有内部链接。但是无论是内部链接还是外部链接,所有的文件作用域变量都具有静态存储期。
线程存储期用于并发程序设计,程序执行可被分为多个线程。具有线程存储期的对象,从被声明时到线程结束一直存在。以关键字_Thread_local声明一个对象时,每个线程都获得该变量的私有备份。
块作用域的变量通常都具有自动存储期。当程序进入定义这些变量的块时,为这些变量分配内存;当退出这个块时,释放刚才为变量分配的内存。这种做法相当于把自动变量占用的内存视为一个可重复使用的工作区或暂存区。例如,一个函数调用结束后,其变量占用的内存可用于存储下一个被调用函数的变量。
变长数组稍有不同,它们的存储期从声明处到块的末尾,而不是从块的开始处到块的末尾。
我们到目前为止使用的局部变量都是自动类别。例如,在下面的代码中,变量number和index在每次调用bore()函数时被创建,在离开函数时被销毁:
void bore(int number){ int index; for (index = 0; index < number; index++) puts("They don't make them the way they used to.n"); return 0;}
然而,块作用域变量也能具有静态存储期。为了创建这样的变量,要把变量声明在块中,且在声明前面加上关键字static:
void more(int number){ int index; static int ct = 0; ... return 0;}
这里,变量ct存储在静态内存中,它从程序被载入到程序结束期间都存在。但是,它的作用域定义在more()函数块中。只有在执行该函数时,程序才能使用ct访问它所指定的对象(但是,该函数可以给其他函数提供该存储区的地址以便间接访问该对象,例如通过指针形参或返回值)。
C使用作用域、链接和存储期为变量定义了多种存储方案。本书不涉及并发程序设计,所以不再赘述这方面的内容。动态分配存储期在本章后面介绍。因此,剩下5种存储类别:自动、寄存器、静态块作用域、静态外部链接、静态内部链接,如表12.1所列。现在,我们已经介绍了作用域、链接和存储期,接下来将详细讨论这些存储类别。