存储类别
int a = 1;
int *p = &a;
int ranks[10];
首先我们定义一下对象,他是指一块内存。他可以存储一个或者多个值。
我们可以看到,变量名a是一个标识符,表示一个变量。
而p这个标识符,他指定了一个存储地址的对象。
ranks声明了一个可容纳10个元素的对象。该数组每个元素也是一个对象。
变量不同的存储类别包含三个特性,作用域,链接属性,存储期.
作用域
变量作用域:表示变量的作用范围,空间维度
有四种:
- 块作用域:局部变量都具有块作用域。
- 文件作用域:直接定义在源文件中的变量所有块之外的变量,具有文件作用域。所以具有文件作用域的变量称为全局变量。
- 函数原型作用域:形参,形参定义到函数结束。
- 函数作用域:语句标签,仅用于goto语句,一般很少。
翻译单元和文件
编译器会把源代码文件和所有包含的的头文件都看成是一个包含信息的单独文件,这个文件被称为一个翻译单元。描述一个文件作用域的变量时,他实际的可见范围是整个翻译单元。
所以一个翻译单元是一个源文件和他所有包含的所有头文件。
链接属性
C变量有三种链接属性:
- 外部链接external
- 内部链接internel
- 无链接
关键字static和extern 在声明中修改标识符的链接属性。
局部变量都是无链接的属性。只有全局变量有外部链接和内部链接两种属性。
我们现在看一下全局变量:
变量具有外部链接属性:他可以在文件外部使用,也就是多文件程序中使用,也叫全局作用域或者程序作用域。
内部链接属性:static修饰的,只在本文件生效,简称文件作用域。
extern:extern修饰的变量,无论被声明多少次,位于不同源文件中都表示同一个实体。
存储期
存储期顾名思义是是变量存在的时间维度。而作用域表示空间维度。这里注意区分。
三个地方存储变量:
- 普通内存
- 运行时堆栈
- 硬件寄存器
举个简单的例子就是函数的局部变量分配的int a = 0;
他会随着函数销毁自动释放。而malloc分配的变量会等到手动free的时候才会释放。
C变量有四种存储期:
- 静态存储期:程序运行期一直存在。全局变量具有静态存储期,不管是全局作用域还是文件作用域的变量**(带不带static的变量)都在程序运行时一直存在**。static修饰的局部变量也有静态存储期,在块销毁的时候他还存在,但是只有在块内才能访问到他。
- 线程存储期:具有线程存储期的变量,以_Thread_local声明的变量,存在于整个线程的生命周期中。
- 自动存储期:块作用域的局部变量,在块作用域内,块结束会自动释放变量内存。
- 动态分配存储期:malloc,和free,用户自己管理。
存储类别
变量三种类型
为了指出该变量是外部变量,
在同一个翻译单元中:我们在使用外部变量可以在前面加上extern关键字,作为声明。
如果不加这个extern 关键字,又声明了一次,那就表示我又创建了一个局部变量在函数中,这会隐藏外部变量。
当然我也可以不声明,在同一个翻译单元中直接使用即可。
如果在不同翻译单元中:也可加extern作为声明引用此外部变量。因为外部变量作用范围是整个程序。
外部变量默认被初始化为0.
多文件共享全局变量
所以多个翻译单元中,使用全局变量作为共享,则在其中一个翻译单元定义一个变量,在其他翻译单元中进行使用该变量之前先使用extern声明该变量,如果不使用extern声明,则不能使用该变量,因为找不到。
静态变量
- 声明在所有函数之外的变量
- 使用static关键字修饰的变量
这两种类型的变量称为静态变量,他们在程序运行之前就会创建,并一定会被初始化一个值。
static关键字
该关键字有两个作用:
- 当变量被声明在代码块之外,则static修饰会改变变量的链接属性,也就是从external改为internal
- 如果变量在代码块内部,static改变的是他的存储类型,变量在就不存在堆栈中而是存储在内存中。
注意:函数的形参不能声明为static。
extern
extern关键字表示声明的变量在别处
如果一个变量在代码块内部,添加extern关键字表示他所引用的是全局变量。
extern链接的实体总是具有静态存储类型。
函数的存储类别
有两种:外部和内部,外部指全局,内部指翻译单元内。
首先第一个表示声明了该函数,并且该函数默认为外部,那么其他所有翻译单元都可以使用。其实这里省略了extern关键字,所以和第三个函数是一样的。
第三个函数显示声明了extern,通常做法这样写表明该函数声明在了其他翻译单元中。但是一般做法是如果要使用某个函数,就把他的头文件包含进来,也就是在当前翻译单元声明了该函数,一起编译就可以直接使用了。
static修饰的函数,只能用于当前翻译单元,
存储类别的选择
默认的而且优先都是选择自动存储类别。
非必要不要声明和定义全局变量,因为他可能被其他人修改而造成你无法正常使用。
除非一种const修饰的全局变量,他在初始化后就不会被修改。