存储类别,链接
一些名称
- (标识符–名称 左值–指定内存位置的内容)
- 存储期描述对象,标识符用于访问对象,可以用作用域和链接描述
关于作用域(易混淆的例子)
注意:有些编译器不支持,需添加声明。
while(x++<33) {int x=100 x++;}
该变量只定义在while循环中,当执行循环体的时候,是新的x被定义为100后递增,每轮迭代结束,新的x变量就消失,进入循环测试条件使用并递增原始的x,再次进入循环,再次创建新的x。若x初始值为30,该循环进入三次,最后输出结果应为34.
新的x被创建和销毁三次- 定义在块内的变量,作用域仅为块内。
若一个变量名同时定义在开头,循环判断条件,循环中。
分别为原始的,索引的,循环体内的。
他作为循环的索引时,隐藏原始的n,后进入循环,新的n隐藏了索引n,结束一轮后,声明在循环体内的n消失,循环头使用索引n进行测试。整个循环结束后,原始的n重新起作用。
全局变量初始化
- 没有做初始化的全局变量会得到0值
- 指针会得到NULL值
- 他们的初始化发生在main以前
- 只能用编译时刻已知的值来初始化全局变量(变量不行)
被隐藏的全局变量
- 如果函数内部 存在与全局变量同名的变量,则全局变量被隐藏
静态本地变量(与全局变量放在一起)
特殊(全局生存区,本地作用域)
- 在本地变量定义时加上static修饰符就成为静态本地变量
- 当函数离开的时候,静态本地变量会继续存在并且保持其值
- 静态本地变量的初始化只会在第一次进入这个函数时做,以后进入函数时会保持上次离开的值(若多次调用函数,函数中有定义,该变量下一次进来的值为上次离开后的,不会重新初始化)。
几种变量
- 块作用域的静态变量
static
静态变量和外部变量在程序被载入内存时已经执行完毕,声明只执行一次,后续反复经过该声明时程序会跳过。
注意:不能在函数形参中使用,古老书中,这种存储类别被称为内部静态存储类别内部指函数内部,非内部链接。 - 寄存器变量
register声明
寄存器变量存储在CPU的寄存器中访问处理会快一些但无法获取地址。
使用时仅只是请求,编译器不一定会实现。但仍然无法获取地址。 - 外部链接的静态变量
该变量具有文件作用域,外部链接和静态存储期属于外部变量,放在所有函数外面(定义式声明:预留空间)。在函数中,可以用
extern声明,跨文件时必须声明。(引入式声明) - 内部链接的静态变量
该存储类别具有静态存储期,文件作用域,和内部链接。
在所有函数外部用static定义。只能用于同一个文件的函数。可用extern声明后使用定义在别处的内部链接的静态变量,但并未改变其内部链接属性。
补充:其他存储类别说明符
extern,static,register,auto…
- auto 该说明符表明变量是自动存储期,只能用于块作用域变量声明中。由于在块中声明的变量本身就具有自动存储期,所以使用auto主要是为了表明要使用与外部变量同名的局部变量的意图。
- typedef与任何内存存储无关,不能使用多个存储类别说明符作为typedef的一部分。
- 例外_Thread_local可以和ststic和extern一起用。
内存管理
程序把他可用的内存分为3部分
-
一部分供具有外部链接,内部链接和无链接的静态变量使用
-
供自动变量使用
-
供动态内存分布
-
自动存储类别的变量 进入变量所在块时存在,程序离开块后消失,这部分内存通常作为栈来处理,新创建的变脸按顺序加入内存,然后以相反顺序进行销毁。
-
动态内存在调用malloc或相关函数时存在,free()后释放。内存块可以在一个函数中创建,另一个函数中销毁。所以,该部分内存用域动态分配会支离破碎,未使用的内存块分散在已使用的内存块之间。并且,使用动态内存通常比使用栈内存慢。
ANSI C类型限定符
- const
- 以它为关键字生命的对象,其值不能通过赋值或递增递减来修改。
- 指针
const float * pf;=float const *pf
*pf指向一个float类型的const的值
pf指向的值不能被改变,而pf本身的值可以改变,可以使指针指向其他const值。
float * const pt;
*pt创建指针pt本身的值不能更改,pt必须指向同一个地址,但是它所指向的值可以改变。
const float * ptr;
ptr既不能指向别处,他所指的值也不能改变
(应用:数组名作为实参传递给函数中,使用const可以不改变数组的值)
例:void display(const int array[],int limit);
(static级const可以放在函数原型和函数头的形式参数的初始方括号中,static新用法:告知编译器如何使用形式参数,目的是让编译器使用这些信息优化函数的编码)
- volatile类型限定符
- 该类型限定符告知计算机,代理(而不是变量所在的程序)可以改变该变量的值。通常被用于硬件地址以及在其他程序或同时运行的线程中共享数据
- 语法与const一样
- 可以同时使用。通常const把硬件时钟设置为程序不能更改的变量,但是可以通过代理改变。同时使用两个限定符,顺序不重要。
- restrict类型限定符
- 只能用于指针,表明该指针是访问数据对象的唯一且初始的方式,且编译器可以自由假定一些优化方案。
- 还可用于函数形参中的指针,编译器可以假定在函数体内其他标识符不会修改该指针指向的数据。
- _Atomic类型限定符
- 管理访问相同数据的不同线程。