本文讨论C语言中的存储类别,包括数据在内存的存储、变量的存储类别、函数的存储类别、生存周期。下图为计算机的存储空间,有寄存器和内存。
一、存储区域
1.寄存器:存放立即参加运算的数据。
2.系统区:存放系统软件。
3.用户程序代码区:存放用户程序的程序代码。
4.库程序代码区:存放库函数的代码。
5.数据区,分为堆区、栈区和静态存储区。
(1)堆区:存放动态变量,即由malloc申请的动态变量。
(2)栈区:存放自动存储类型的变量,包括函数和复合语句中的局部变量等。
(3)静态存储区:存放具有显式声明的静态类型的变量。
二、变量的存储类别
1.静态变量
静态变量:这里的静态指的一般程序设计语言概念中的静态变量,即程序中显式声明的变量。静态变量有一个名字,在编译时,编译程序已经给静态变量分配了内存空间。
静态变量的存储类型分为两大类:静态(包括static和extern)和自动(包括auto)
auto:自动存储类别,默认的存储类别
存储在栈区,作用域在声明它的函数和复合语句中。auto具有本地生存期,当声明自动变量的个体执行结束,自动变量结束生存周期,不再存在。
auto int i; int j;//默认为auto存储类别
static:静态存储类别
存储在静态存储区。静态变量分为静态局部变量和静态全局变量。
静态局部变量:具有本地生存期,生存周期是整个程序,在程序结束后,生存期结束并被删除。但作用域仅在声明它的个体中。离开复合语句或函数,静态变量依然存在但不能被访问。再次进入声明该静态变量的个体时,可以继续使用,而且保留浅一些使用留下的值。静态局部变量只能在开始时初始化一次。
全局局部变量:生存周期是包含它声明的整个程序文件,可随时访问。
{ static int a; ... }//作用域仅在复合语句内,同auto //离开复合语句,静态局部变量存在但不能被使用,值保持上一次的使用
extern外部存储类别
尽可用作全局变量的存储类型。存储在静态存储区。在顶层声明中,extern是默认存储类别,所有未加extern的全局变量均被视为外部变量。在使用其他文件的外部变量时,使用extern说明符,这样在连接时分配相同的存储区,占用相同的存储空间。若两个文件中的同名全局变量都没有使用extern,会在连接时出现错误,因为他们都被声明成全局的外部变量,都分配了存储空间,产生冲突。
文件1:
int a;//extern是全局变量默认的存储类别
文件2
extern int a;//使用文件1的局部变量,占用相同存储空间
注:register寄存器存储类型可以显式声明,表明变量要分配在计算机CPU中的寄存器中,对于频繁访问的变量,可以节约时间,提高程序运行效率。但是,寄存器数量很有限,若寄存器边纳凉太多,将被认为是auto类型。
2.动态变量
动态变量:是指使用申请空间函数(如malloc)动态申请的空间,存放在堆区。动态变量没有显式声明,在编译的时候不分配(也无法分配)空间。在程序运行时,动态变量由指针标识。使用完毕后,使用释放空间函数(如free)等释放。动态函数具有动态生存期,生存周期是显式实现的。
float *p; p=(float*)malloc(sizeof(float));//生存周期开始 ... free(p);//生存周期结束
三、函数的存储类别
C语言的函数可以被定义成static和extern两种存储类别。
static:内部函数
与变量的static存储类别相区别。内部函数的作用域调用范围仅限于本文件,在不同源文件中的同名静态函数不会混淆。
extern:外部函数
函数默认的存储类别。外部函数在一个源文件中被定义,在其他源文件可以使用。在一个源程序文件中调用其它源程序文件中定义的外部函数时,必须在本源文件中用函数原型说明它,并加上extern前缀。
所有的函数都具有静态生存期,即分配的空间在程序执行前开始,保持到程序执行结束为止。
文件1:
int f(float x)//函数默认的存储类别是外部函数 { ... }
文件2:
extern int f(foat);//使用外部函数