存储类(storage class)说明变量在何处分配、可见范围、生命周期以及未显式初始化时的默认值。C 语言中有 auto、static、register、extern 四类,其中 static 在静态存储相关章节亦有讨论。
四种存储类对照
| 存储类 | 作用域 | 默认初值 | 存储位置 | 生命周期 |
|---|---|---|---|---|
auto | 块内 | 不确定(自动变量) | 内存(栈帧) | 至块结束 |
static | 块内或文件内 | 0 | 静态存储区 | 至程序结束 |
register | 块内 | 不确定 | 可能位于寄存器 | 至块结束 |
extern | 跨翻译单元 | 0(全局对象) | 静态存储区 | 至程序结束 |
auto:默认的局部变量
块内声明的变量默认为 auto,故该关键字很少显式写出:
int main(void) {
auto int x = 10;
printf("%d", x);
return 0;
}自动变量仅在声明所在的块内可见;未初始化时值不确定;离开块后所占栈空间可被复用。函数本身不使用 auto 存储类说明。
static:跨调用保留值的局部变量
块内 static 变量只初始化一次,之后各次进入该块仍保留上次的值:
void counter(void) {
static int count = 0;
count++;
printf("Count = %d\n", count);
}
counter(); /* Count = 1 */
counter(); /* Count = 2 */普通自动局部变量每次进入函数都会重新分配;static 局部变量存放在静态存储区,生命周期延续到程序结束。文件作用域的 static 还可限制符号仅在当前翻译单元内链接。
register:提示使用寄存器
register 向实现建议将变量放在寄存器中以提高访问速度:
register int i;
for (i = 0; i < 5; i++) {
printf("%d ", i);
}是否采纳由编译器决定;寄存器数量有限。对 register 对象取地址可能不被允许。现代编译器常自动完成寄存器分配,该关键字使用较少。
extern:引用其他翻译单元中的定义
多文件程序中,若变量在某文件中定义,其他文件可用 extern 声明以使用同一对象:
/* printVar.c */
int globalVar = 100;
/* main.c */
#include <stdio.h>
extern int globalVar;
int main(void) {
printf("全局变量是 %d\n", globalVar);
return 0;
}编译链接示例:
gcc main.c printVar.c -o mainextern 声明不分配存储,仅说明标识符在别处已有定义。全局变量未初始化时默认为 0。
选用思路
- 需在多次函数调用间保留局部状态 → 块内
static。 - 使用定义在其他源文件中的全局对象 →
extern声明。 - 普通局部变量、随块创建销毁 → 默认
auto(可省略关键字)。
本节归纳了四类存储类的差异。下一节结合程序内存布局说明栈、堆与各数据段如何承载不同存储类别的对象。