C语言存储类 #
一、存储类概述 #
1.1 什么是存储类 #
存储类定义变量的以下特性:
- 存储位置:内存中的位置(栈、堆、全局区等)
- 作用域:变量可见的范围
- 生命周期:变量存在的时间
- 初始值:未初始化时的默认值
1.2 四种存储类 #
| 存储类 | 关键字 | 存储位置 | 作用域 | 生命周期 |
|---|---|---|---|---|
| 自动 | auto | 栈 | 局部 | 函数内 |
| 静态 | static | 全局区 | 局部/全局 | 程序期 |
| 外部 | extern | 全局区 | 全局 | 程序期 |
| 寄存器 | register | 寄存器 | 局部 | 函数内 |
二、auto存储类 #
2.1 基本用法 #
auto是局部变量的默认存储类,通常省略:
c
void func() {
auto int a = 10;
int b = 20;
}
2.2 特点 #
c
#include <stdio.h>
void func() {
int a = 10;
printf("func: a = %d\n", a);
a = 20;
}
int main() {
func();
func();
return 0;
}
输出:
text
func: a = 10
func: a = 10
特点:
- 存储在栈区
- 作用域限于函数内
- 函数调用时创建,返回时销毁
- 未初始化值为随机值
2.3 内存布局 #
text
栈区
┌──────────────┐
│ 局部变量 │ ← auto变量
│ 函数参数 │
│ 返回地址 │
└──────────────┘
三、static存储类 #
3.1 静态局部变量 #
c
#include <stdio.h>
void counter() {
static int count = 0;
count++;
printf("调用次数: %d\n", count);
}
int main() {
counter();
counter();
counter();
return 0;
}
输出:
text
调用次数: 1
调用次数: 2
调用次数: 3
特点:
- 存储在全局区
- 只初始化一次
- 值在函数调用之间保持
- 作用域仍限于函数内
3.2 静态全局变量 #
c
#include <stdio.h>
static int global_var = 100;
void func() {
printf("func: %d\n", global_var);
}
int main() {
printf("main: %d\n", global_var);
func();
return 0;
}
特点:
- 作用域限于当前文件
- 其他文件无法访问
3.3 静态函数 #
c
static int add(int a, int b) {
return a + b;
}
int main() {
int result = add(1, 2);
printf("%d\n", result);
return 0;
}
特点:
- 只能在当前文件内调用
- 避免命名冲突
3.4 初始化规则 #
c
#include <stdio.h>
void func() {
static int a;
static int b = 0;
int c;
printf("static a: %d\n", a);
printf("static b: %d\n", b);
printf("auto c: %d\n", c);
}
int main() {
func();
return 0;
}
输出:
text
static a: 0
static b: 0
auto c: 随机值
规则:
- 静态变量未初始化,默认为0
- 自动变量未初始化,值为随机
3.5 应用场景 #
计数器:
c
int get_next_id() {
static int id = 0;
return ++id;
}
单例模式:
c
typedef struct {
int value;
} Singleton;
Singleton* get_instance() {
static Singleton instance = {0};
return &instance;
}
缓存:
c
int fibonacci(int n) {
static int cache[100] = {0};
if (n <= 1) return n;
if (cache[n] != 0) return cache[n];
cache[n] = fibonacci(n-1) + fibonacci(n-2);
return cache[n];
}
四、extern存储类 #
4.1 声明外部变量 #
c
#include <stdio.h>
extern int global_var;
int main() {
printf("%d\n", global_var);
return 0;
}
4.2 跨文件使用 #
file1.c:
c
#include <stdio.h>
int global_var = 100;
void print_global() {
printf("global_var = %d\n", global_var);
}
file2.c:
c
#include <stdio.h>
extern int global_var;
extern void print_global();
int main() {
printf("main: %d\n", global_var);
global_var = 200;
print_global();
return 0;
}
编译:
bash
gcc file1.c file2.c -o program
./program
输出:
text
main: 100
global_var = 200
4.3 extern声明 vs 定义 #
声明(不分配内存):
c
extern int global_var;
定义(分配内存):
c
int global_var = 100;
4.4 头文件使用 #
global.h:
c
#ifndef GLOBAL_H
#define GLOBAL_H
extern int global_var;
void print_global(void);
#endif
global.c:
c
#include "global.h"
#include <stdio.h>
int global_var = 100;
void print_global(void) {
printf("global_var = %d\n", global_var);
}
main.c:
c
#include "global.h"
int main() {
print_global();
global_var = 200;
print_global();
return 0;
}
4.5 注意事项 #
避免重复定义:
c
int global_var = 100;
int global_var = 200;
声明与定义类型一致:
c
int global_var;
extern float global_var;
五、register存储类 #
5.1 基本用法 #
c
void func() {
register int i;
for (i = 0; i < 1000000; i++) {
}
}
5.2 特点 #
优点:
- 访问速度快
- 适合频繁使用的变量
限制:
- 不能取地址
- 数量有限
- 只是建议,编译器可能忽略
5.3 使用示例 #
c
#include <stdio.h>
#include <time.h>
int main() {
clock_t start, end;
start = clock();
for (register int i = 0; i < 1000000000; i++) {
}
end = clock();
printf("时间: %f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
return 0;
}
5.4 不能取地址 #
c
register int a = 10;
int* p = &a;
5.5 现代编译器 #
现代编译器优化能力强,通常不需要手动使用register:
c
for (int i = 0; i < 1000000; i++) {
}
编译器会自动将频繁使用的变量放入寄存器。
六、存储类对比 #
6.1 对比表 #
| 特性 | auto | static | extern | register |
|---|---|---|---|---|
| 存储位置 | 栈 | 全局区 | 全局区 | 寄存器 |
| 作用域 | 局部 | 局部/全局 | 全局 | 局部 |
| 生命周期 | 函数内 | 程序期 | 程序期 | 函数内 |
| 初始值 | 随机 | 0 | 0 | 随机 |
| 可取地址 | 是 | 是 | 是 | 否 |
6.2 内存布局 #
text
内存布局
┌──────────────┐ 高地址
│ 栈区 │ ← auto, register
│ ↓ │
│ ↑ │
│ 堆区 │
├──────────────┤
│ 全局区 │ ← static, extern
│ (BSS/Data) │
├──────────────┤
│ 常量区 │
├──────────────┤
│ 代码区 │
└──────────────┘ 低地址
七、存储类最佳实践 #
7.1 选择原则 #
| 场景 | 推荐存储类 |
|---|---|
| 普通局部变量 | auto(默认) |
| 需要保持值 | static |
| 跨文件共享 | extern |
| 频繁访问 | 让编译器优化 |
7.2 避免滥用全局变量 #
问题:
c
int global;
void func1() {
global = 10;
}
void func2() {
global = 20;
}
int main() {
func1();
func2();
printf("%d\n", global);
return 0;
}
改进:
c
void func1(int* p) {
*p = 10;
}
void func2(int* p) {
*p = 20;
}
int main() {
int value;
func1(&value);
func2(&value);
printf("%d\n", value);
return 0;
}
7.3 使用static限制作用域 #
c
static int module_var;
static void helper_func() {
}
void public_func() {
helper_func();
}
7.4 头文件规范 #
正确做法:
c
#ifndef MODULE_H
#define MODULE_H
extern int module_var;
void module_func(void);
#endif
八、总结 #
auto #
- 默认存储类
- 局部变量
- 栈区存储
- 函数返回后销毁
static #
- 保持变量值
- 限制作用域
- 全局区存储
- 程序结束销毁
extern #
- 跨文件共享
- 声明外部变量
- 全局区存储
- 程序结束销毁
register #
- 建议存入寄存器
- 访问速度快
- 不能取地址
- 现代编译器自动优化
选择建议 #
- 优先使用局部变量
- 必要时使用static
- 谨慎使用extern
- 让编译器优化register
下一步,让我们学习运算符!
最后更新:2026-03-26