Skip to content

static

在 C 语言中,static 是一个非常“分裂”的关键字。因为它用在不同的地方,意思是完全不一样的。

简单来说,它的核心作用就两个:“长生不老”“与世隔绝”

我们需要分两种情况来看:


1. 用在函数内部:Static 局部变量 —— “长生不老”

这是 static 最神奇的用法。

普通局部变量 (没有 static)

  • 命运: 就像**“住酒店”**。
  • 过程: 函数执行时,变量被创建(入住);函数结束时,变量被销毁(退房,房间被清理)。下次再调用这个函数,变量又是新的,之前的数值全丢了。
  • 存储位置: 栈 (Stack)。

静态局部变量 (有 static)

  • 命运: 就像**“买房子”**。
  • 过程:
    • 初始化: 只有第一次运行函数时会初始化一次(装修)。
    • 存活: 函数运行结束,变量不销毁! 它依然保留着刚才的值,静静地待在内存里。
    • 重逢: 下次再调用这个函数时,它直接使用上次留下的值。
  • 存储位置: 静态存储区 (.data 或 .bss 段),而不是栈。

代码对比:

C

void count_normal() {
    int a = 0; // 普通变量
    a++;
    printf("普通: %d\n", a);
}

void count_static() {
    static int b = 0; // 静态变量(这句话只在第一次执行时有效)
    b++;
    printf("静态: %d\n", b);
}

int main() {
    // 第一次调用
    count_normal(); // 输出 1
    count_static(); // 输出 1

    // 第二次调用
    count_normal(); // 输出 1 (a 被重置为 0,再加 1)
    count_static(); // 输出 2 (b 记得上次变成了 1,现在加 1 变成 2)
  
    // 第三次调用
    count_normal(); // 输出 1
    count_static(); // 输出 3 (b 继续累加)
}

应用场景:

当你需要一个函数**“记住”**它上一次被调用时的状态(比如记录按键按下的次数、秒表计时),但又不想用全局变量污染代码时,就用 static 局部变量。


2. 用在函数外部:Static 全局变量/函数 —— “与世隔绝”

这时候,static 的作用就变成了控制可见范围 (Scope)

普通全局变量 (没有 static)

  • ***范围:***整个工程可见。
  • 如果在 main.c 里定义了 int key_state = 0;
  • 那么在 delay.c 里,只要写一句 extern int key_state;,就可以随意读取和修改这个变量。
  • 风险: 容易重名冲突,也容易被别的程序员误改。

静态全局变量 (有 static)

  • ***范围:***仅当前文件 (.c) 可见。
  • 如果在 main.c 里定义了 static int key_state = 0;
  • 那么这个变量就是 main.c私有财产。别的 .c 文件就算用 extern 也找不到它,甚至别的 .c 文件也可以定义一个同名的 static int key_state,互不干扰。

Static 函数

同理,如果你在函数前加 static(比如 static void Sensor_Init(void)),那么这个函数只能在当前的 .c 文件里被调用,别的 .c 文件看不见它。

应用场景:

这就是面向对象编程中 “封装” (Encapsulation) 的 C 语言版实现。

  • 你在写一个模块(比如 motor.c),里面有一些辅助函数和变量,你只希望模块内部自己用,不想让外部(比如 main.c)看到或乱动,就全部加上 static

总结一张表

类型位置生命周期作用域 (谁能看见)存储位置
普通局部变量函数内函数结束即死仅函数内栈 (Stack)
Static 局部变量函数内程序结束才死仅函数内 (但活着)静态区
普通全局变量函数外程序结束才死所有文件静态区
Static 全局变量函数外程序结束才死仅当前文件静态区

一句话口诀:

  • 函数里面加 static为了记性好(记住上一次的值)。
  • 函数外面加 static为了私密性(不让别的文件乱动)。