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