一、存储类别
C语言有自动(auto) 、寄存器(register)、 静态(static)、外部变量(extern)四种存储类别,每种存储类别具有不同的 存储期(Storage duration)、作用域(scope)、 链接(linkage)。
C语言提供几种存储方法,来存放在内存中变量的值。
硬件方面,被存储的每一个值都会占用一定的物理内存,C语言把这样的一块内存叫对象(Object)。
软件方面,程序需要一种方法访问对象。声明变量是一种方法。
有三个地方可以用于存储变量:普通内存、运行时堆栈、硬件寄存器。
1. 作用域:
作用域又称作用范围。在程序中出现的各种标识符,它们的作用域是不同的。标识符只能在说明它或定义它的范围内是“可见的”,即是可以进行存取或访问操作的;而在该范围之外是“不可见”的,也就是指不可以进行存取或访问操作的。
(1)块作用域
任何位于一对花括号之间是一个代码块, 代码块内声明的标识符只在该代码块内起作用,,例如在main函数里声明的变量只在main函数里起作用,在自定义函数里声明的变量只在自定义函数里起作用。
(2)函数作用域
函数作用域只适用于goto语句的标签,作用将goto语句的标签限制在同一个函数内部,以及防止出现重名标签
(3)函数原型作用域
原型作用域只适用于那些在函数原型中声明的参数名。函数在声明的时候可以不写参数的名字(但参数类型是必须是写上的),其实函数原型的参数名还可以随便写一个名字,不必与形式参数相匹配。
(4)文件作用域
作用范围是整个源文件,例如定义的全局变量或内部函数和外部静态类变量,其作用域为文件作用域。
2.链接
(1)外部链接(external)
多个文件中声明的同名标识符表示同一个实体,可以在多个文件程序中使用。
只有具备文件作用域的标识符才能拥有external或internal的链接属性,其他作用域的标识符都是none属性。默认情况下,具备文件作用域的标识符拥有external属性。也就是说该标识符允许跨文件访问。对于external属性的标识符,无论在不同文件中声明多少次,表示的都是同一个实体。
(2)内部链接(static)
单个文件中声明的同名标识符表示同一个实体,只能在一个编译单元中使用。
(3)无链接(none)
声明的同名标识符被当作独立不同的实体,具有块作用域、函数作用域、函数原型作用域的变量都是无链接变量,表示变量的可见范围属于块、函数私有。
使用static关键字可以使得原先拥有external属性的标识符变为internal属性。
这里有两点需要注意:
1.使用static关键字修改链接属性,只对具有文件作用域的标识符生效(对于拥有其他作用域的标识符是另一种功能)
2.链接属性只能修改一次,也就是说一旦将标识符的链接属性变为internal,就无法变回external了
3. 存储期
作用域与链接描述了标识符的可见性,存储期描述了通过这些标识符访问的对象的生存期。
(1)静态存储期
程序执行期间一直存在,文件作用域变量都是静态存储期。
(2)线程存储期
用于并发程序设计,线程结束之前一直存在。
(3)自动存储期
块作用域变量具有自动存储期,要使让块作用域变量具有静态存储期,在变量前加 static 关键字即可。
(4)动态分配存储期
用new 或者malloc分配的内存,如果不主动释放,在整个程序都占有内存
总结如下
存储类别 | 存储期 | 作用域 | 链接 | 声明方式 |
---|---|---|---|---|
自动(auto) | 自动 | 块 | 无 | 块内声明 |
寄存器(register) | 自动 | 块 | 无 | 块内,关键字 register |
静态外部链接(static with external linkage) | 静态 | 文件 | 外部 | 所有函数外 |
静态内部链接(static with interanl linkage) | 静态 | 文件 | 内部 | 所有函数外,关键字 static |
静态块作用域(static with no linkage) | 静态 | 块 | 无 | 块内,关键字 static |
外部变量(extern) | 静态 | 文件 | 外部 | 所有函数外 |
示例
#include<stdio.h>
int a ; //文件作用域 , 静态外部链接 , 其他文件可以使用
static int b ; //文件作用域 , 静态内部链接 , 该文件私有
extern char str ; //标识符str是在其他文件中定义的全局变量
int main(void)
{
int n = 5 ; //块作用域 , 无链接 , 自动auto变量,main函数结束后消失
static int m ; //静态块作用域 , 无链接
register int j ; //寄存器变量,
printf("%d" , n ) ;
return 0 ;
}