C Primer+Plus(十二)(1)
第12章 存储类、链接和内存管理
12.1存储类
存储类,也可称为存储模型,即一个变量,它在内存中是如何存放,生存多久,以及作用范围。先说明几个名词的含义:
12.1.1作用域
作用域描述的是一个变量(标识符)可以在程序哪些区域被使用,包括:代码块作用域、函数原型作用域、文件作用域。
int x; //此处x作用域为整个程序文件 main(void) { int functiona(int b); //此处为函数声明,b只是参数表示,不是特指变量 int a; //a作用域从此处至main函数结束 for(int i=0;i<a;i++) //i作用域仅为for循环代码段 {int m; //m作用域从此处至for循环结束 functiona(m);int functionb(int a1){}
functionb(m); ...; } } int functiona(int x) //此处x作用域为函数原型,不同于程序开始处的x,程序开始处的x变量此时已被屏蔽 {int a; //a作用域从此处至functiona函数结束,不同于main中a,main中a此时已被屏蔽 ... } //被调函数结束,被屏蔽的x和a解封
说明,对于上例程序中开头的变量x,在程序functiona和functionb中均是可用的,只是因为functiona中定义了一个同名变量,导致其在functiona中被屏蔽。
12.1.1链接
链接是指什么?粗略看完整章,用自己的理解说明一下:一个变量,除去在程序文件中的作用域之外,还可以在哪里使用?若可以被其他程序文件使用,则称外链接;若可以在本文件内部任何地方使用,则称内链接。而仅具有代码块作用域或函数原型作用域的变量不具备链接性,称为空链接。
int a=5; //具备文件作用域,具备外链接性,称为外链接 static int b=6; //具备文件作用域,内链接 int main(void) {... }
12.1.3存储时期
C变量有两种存储时期:静态存储时期(static storage duration)和自动存储时期(automatic storage duration)。
静态存储时期表示该类变量在程序执行期间将一直存在。具有文件作用域的变量具有静态存储时期特性。
自动存储时期表示该类变量仅在程序运行在其作用域内时存在,一旦程序退出作用域,存储该变量的内存将被释放。代码块作用域和函数原型作用域的变量一般均为自动存储类型。
在上述三个概念介绍后,提出5种存储类型:
存储类 时期 作用域 链接 声明方式
自动 自动 代码块 空 代码块内
寄存器 自动 代码块 空 码块内,使用关键字register
具有外部链接的静态 静态 文件 外部 所有函数之外
具有内部链接的静态 静态 文件 内部 所有函数之外,使用关键字static
空链接的静态 静态 代码块 空 代码块内,使用关键字static
依次介绍:
12.1.4自动存储类型的变量
具有:自动存储时期,代码块作用域,空链接特性。一般情况,在代码块头部或函数头部定义的变量都属于自动存储类型。
int main() {int a; //a属于自动存储类 auto int b; //也可用auto关键字显式声明自动存储类变量b int f1(); ... } int f1(void) { int m; //正常声明一个自动存储类变量 auto int n; //也可通过auto ... }
自动存储时期意味着程序进入该变量所处代码块时候,变量被分配内存空间,当程序结束该代码块时候,自动变量就不存在了,即所占内存被释放。
*对于自动存储类变量,若未被初始赋值,则其值是其所占内存单元里的数值,也就是不可预知的。
12.1.5寄存器存储类变量
当希望变量可被更快速的访问和操作,因为VPU访问寄存器单元肯定比访问内存更快速,则可选用该类型。
声明形式:register int a;通过该声明使得在程序编译到此句时,给变量a分配寄存器(若寄存器不够用,则分配相对更快速的内存单元)。因多数情况下该声明后分配存储区为寄存器,而寄存器的地址是不可读的,则该类变量无法进行&操作,因为取不到地址。
12.1.6具有代码块作用域的静态变量
静态变量是指变量的存储位置固定不动。回想一下,在程序文件头声明定义的变量都是静态变量;另一种静态变量则是具有代码块作用域的静态变量,它的作用域仅限于代码块,同时具备空链接性,但它的生命周期是贯穿从定义初始,到程序结束的。
#include<stido.h> int main(void) { int i; void fs(); for(i=0;i<2;i++) fs(); return 0; } void fs() {int x=1; static y=2; printf("%d-%d",x++,y++); }
上程序在TC3.0下运行结果如下:
1-2
1-3
函数fs体内定义了两个变量,x是明显的自动存储类变量,作用域和生命周期都仅限于每一次调用中的fs,每一次调用fs都会临时给每次的x分配内存空间,并初始化数值1;而y是静态存储类,因其在函数体内定义,其作用域也仅限于函数体,但其在整个程序运行期间(从y被定义至程序结束)都在固定地址存放,并且只有当函数fs被调用时候才可以被使用。
代码块作用域静态存储类变量不能用于函数的参数。
12.1.7具有外部链接的静态变量
该类变量具有文件作用域、静态存储类、外部链接特性。也称为“外部变量”。在程序中所有函数之外定义声明一个变量,则创建了外部变量。
(1)定义声明:是指外部变量的初始创建。
(2)内部引用声明:指在同一文件中,函数在使用该外部变量时候通过关键字extern的引用声明,该声明一般可省略。
(3)外部引用声明:在其他文件中若要使用另一文件内创建的外部变量,则必须显式声明。
------file a--------- int tsa; //定义声明外部变量tsa int tsb=1; //也可定义声明外部变量tsb,并初始化 int main() { int i,j; ... } void f1() { extern int tsa; //因在同一文件里,该处声明也可以省略 .... } ---------------------------- ---------file b--------- #include"a.h" //包含引用声明变量的定义文件 extern int tsb; //引用声明,必须的,因为该变量的定义不在同一文件中 int main() {... }
再看下例:
#include <stdio.h> int x1; //定义声明外部变量x1 int main() { int x1; //定义声明自动变量x1,和上述外部变量只是同名 .... //在main代码块里,只有自动变量x1起作用 }
*若外部变量定义声明时候未初始赋值,则其初始值为0。并且外部变量只可以用常量表达式来初始化赋值。
例如对于外部变量a: int a=2*b; //是非法的,即便变量b事先已被定义
*定义和声明:区别在于系统何时给变量分配存储空间则称为定义。对于引用声明关键词extern的使用,若和外部变量定义语句在同一文件中则可省略;若不在同一文件则该关键字是不可省略的。对于应用声明,还需要注意如下:
int a1=2; //定义声明一个外部变量a1,并赋值2 int main() { extern int a1; //正确,但可省略 extern int a1=3; //错误,该语句仅是引用声明,而不能赋值;即便理解为定义声明一个外部变量也应该是在所有函数之外进行 //若忽略上两句 a1=3; //正确 ... }
12.1.8具有内部链接的静态变量
该类变量具有:静态存储时期,文件作用域以及内链接特性。在所有函数外部通过关键字static定义声明该类变量。
(1)定义声明:是指外部变量的初始创建。
(2)内部引用声明:指在同一文件中,函数在使用该外部变量时候通过关键字extern进行声明,该声明一般可省略。但该声明不改变内部链接特性。