6、静态变量:static关键字,静态局部变量与静态全局变量
讲函数作用域,绕不开一个关键字——static。
说实话,很多初学者一看到 static 就头大。什么静态局部变量、静态全局变量,名字听着就绕。我当年学的时候也懵过,直到在项目里踩了坑,才真正搞明白它到底在干什么。
今天咱们就把 static 彻底说清楚。
6.1 static 到底在干什么?
一句话总结:static 控制的是变量的“生命周期”和“作用域”。
具体来说:
- 静态局部变量:生命周期变成整个程序运行期间,但作用域还是只在函数内部。
- 静态全局变量:作用域被限制在当前源文件内,其他文件无法访问。
说白了,static 就是给变量加了一把锁——要么让它活得更久,要么让它藏得更深。
核心记忆点:
- static 局部变量 = 函数内的“永久居民”
- static 全局变量 = 文件内的“私有财产”
6.2 静态局部变量:函数内的“记忆体”
先看一个最经典的例子:
#include <stdio.h>
void counter() {
static int count = 0; // 静态局部变量
count++;
printf("count = %d\n", count);
}
int main() {
counter(); // 输出 count = 1
counter(); // 输出 count = 2
counter(); // 输出 count = 3
return 0;
}
看到了吗?每次调用 counter(),count 的值都在累加。它没有被重置为 0。
为什么会这样?
因为 静态局部变量只初始化一次。程序启动时,count 就被分配了内存,并且初始化为 0。之后每次进入 counter(),都不会再执行初始化语句。它就像函数内部的一个“记忆体”,记住了上一次离开时的值。
我的经验:
我在做嵌入式设备的状态机时,经常用静态局部变量来保存当前状态。比如一个按键扫描函数,需要记住上一次按键的状态,用 static 变量就非常方便,既不会被外部干扰,又能跨函数调用保持数据。
6.3 静态全局变量:文件内的“私有变量”
再看静态全局变量。它和普通全局变量的区别,在于链接属性。
普通全局变量,默认是 external 链接属性。什么意思?就是你在 a.c 里定义了一个全局变量,b.c 里用 extern 声明一下就能用。
但静态全局变量不一样。它被限制在定义它的源文件内,其他文件即使写了 extern 也访问不到。
看代码:
// file: module.c
static int secret_value = 42; // 静态全局变量
void set_secret(int v) {
secret_value = v;
}
int get_secret() {
return secret_value;
}
// file: main.c
extern int secret_value; // 错误!链接失败
// 只能通过 set_secret() / get_secret() 来访问
这种设计,说白了就是信息隐藏。你不想让外部直接操作内部数据,那就用 static 把它藏起来,只暴露接口函数。
注意:
我曾经在一个多人协作的项目里,看到有人把全局变量全写成 static,结果其他模块想用的时候发现根本链接不上。后来改成了用接口函数封装——该藏的藏,该露的露,代码清晰多了。
6.4 静态函数:比静态全局变量更常见的用法
其实 static 还能修饰函数。用法和静态全局变量一样:把函数的作用域限制在当前源文件内。
// file: helper.c
static void internal_helper() {
// 这个函数只能在本文件内调用
printf("内部辅助函数\n");
}
void public_api() {
internal_helper(); // 可以调用
// 其他逻辑
}
这种写法在模块化编程里非常常见。你想想看,一个模块内部可能有十几个辅助函数,但对外只需要暴露两三个接口。那剩下的函数全部加上 static,既防止外部误调用,也让接口更清晰。
我的习惯:
只要一个函数不是对外接口,我必定加 static。这不是强迫症,而是工程规范。你去看 Linux 内核源码,里面大量使用 static 函数,目的就是减少命名冲突、提高模块内聚性。
6.5 一张图看懂 static 的作用
下面这张 SVG 图,把 static 对变量和函数的影响总结得很清楚:
6.6 避坑指南:static 的常见误区
我见过不少新手在 static 上栽跟头,这里列几个最常见的:
- 误区一:以为静态局部变量在整个程序里都能访问
不对。它只是生命周期变长了,作用域还是局限在函数内部。出了函数,你就访问不到它。 - 误区二:忘记静态局部变量只初始化一次
如果你在函数里写static int x = 10;,那这个赋值只在第一次进入函数时执行。后面再进来,x 保留的是上次的值。 - 误区三:滥用静态全局变量
有些人觉得全局变量不安全,就把所有全局变量都改成 static。结果模块之间无法共享数据,反而增加了接口复杂度。该用 extern 的时候还是要用。
我曾经踩过的坑:
有一次写一个多文件项目,我在 a.c 里定义了一个静态全局变量,然后在 b.c 里用 extern 声明想引用它。编译直接报链接错误。我查了半天才发现——static 全局变量根本不能被外部访问。后来改成用接口函数封装,问题解决。
6.7 总结一下
static 关键字,说白了就两件事:
- 用在局部变量上:让它活得更久(整个程序运行期间)
- 用在全局变量或函数上:让它藏得更深(只在本文件内可见)
记住这个原则,你就能用好 static。
嗯,关于静态变量的内容就讲到这里。下一章咱们聊聊递归函数——那个让初学者又爱又恨的话题。
公众号:蓝海资料掘金营,微信 deep3321