static 是 C 语言中一个非常重要且多用途的关键字,它的核心作用是改变变量的生命周期和作用域,根据它出现位置的不同,其行为和用途也完全不同。

(图片来源网络,侵删)
主要可以分为以下三种情况:
- 在函数内部使用:修饰局部变量。
- 在所有函数外部使用:修饰全局变量。
- 用于函数定义:修饰函数。
在函数内部:修饰局部变量(最常见用法)
当一个局部变量被 static 修饰后,会发生两件事:
- 改变生命周期:该变量不再存储在栈上,而是存储在静态存储区(或叫全局数据区),这意味着它的生命周期不再局限于函数的调用,而是与整个程序的生命周期相同,即使函数执行结束,这个变量的值也不会被销毁。
- 改变存储位置:它不再随函数的调用而创建,随函数的结束而销毁,它只会在程序开始时初始化一次(如果未初始化,则默认为0)。
- 作用域不变:它的作用域仍然限制在定义它的函数内部,外部无法访问。
作用:
实现“记忆功能”,让函数能够“上一次调用时的状态。
示例:
#include <stdio.h>
// 普通局部变量
void normal_counter() {
int count = 0; // 每次调用都会重新初始化为0
count++;
printf("Normal counter: %d\n", count);
}
// static局部变量
void static_counter() {
static int count = 0; // 只在程序开始时初始化一次
count++;
printf("Static counter: %d\n", count);
}
int main() {
printf("--- Calling normal_counter() ---\n");
normal_counter(); // 输出: Normal counter: 1
normal_counter(); // 输出: Normal counter: 1 (重新初始化了)
normal_counter(); // 输出: Normal counter: 1 (重新初始化了)
printf("\n--- Calling static_counter() ---\n");
static_counter(); // 输出: Static counter: 1
static_counter(); // 输出: Static counter: 2 (记住了上次的值)
static_counter(); // 输出: Static counter: 3 (记住了上次的值)
return 0;
}
输出结果:

(图片来源网络,侵删)
--- Calling normal_counter() ---
Normal counter: 1
Normal counter: 1
Normal counter: 1
--- Calling static_counter() ---
Static counter: 1
Static counter: 2
Static counter: 3
其他特点:
- 初始化:
static局部变量只初始化一次,如果你在函数内部多次调用,初始化语句(如static int count = 0;)只会在第一次执行时有效。 - 默认值:如果未显式初始化,
static变量会被自动初始化为0(对于指针是NULL)。
在所有函数外部:修饰全局变量
全局变量本身就具有文件作用域(整个文件可见)和静态生命周期(程序全程存在),当 static 修饰全局变量时,它只改变其作用域。
- 作用域限制:该全局变量的作用域被限制在当前源文件(.c文件)内,其他文件(即使通过
extern声明)也无法访问它。 - 生命周期不变:它的生命周期仍然是整个程序。
作用:
实现文件封装或信息隐藏,避免全局变量名在不同文件间的冲突,这是一种良好的编程实践,可以防止意外的全局变量污染。
示例:
文件 file1.c
#include <stdio.h>
// 这是一个static全局变量,只能在file1.c内部访问
static int global_var = 100;
void print_global_var() {
printf("In file1.c, global_var is: %d\n", global_var);
}
文件 file2.c

(图片来源网络,侵删)
#include <stdio.h>
// 尝试访问file1.c中的static全局变量,这会导致编译错误
// extern int global_var; // 如果取消注释并编译,会报 "undefined reference to `global_var'" 错误
void another_function() {
// printf("Trying to access global_var from file2.c: %d\n", global_var); // 编译错误!
printf("This is in file2.c.\n");
}
文件 main.c
#include <stdio.h>
// 声明外部函数
void print_global_var();
void another_function();
int main() {
print_global_var(); // 可以正常调用,因为它是一个普通函数
another_function();
return 0;
}
编译与运行:
当你编译这些文件时,file2.c 中的代码无法访问 file1.c 中的 global_var,从而实现了模块间的隔离。
用于函数定义:修饰函数
static 修饰函数的效果与修饰全局变量非常相似。
- 作用域限制:该函数的作用域被限制在当前源文件(.c文件)内,其他文件无法通过函数声明来调用它。
- 链接属性:它成为了内部链接的函数,而普通函数是外部链接的。
作用:
同样是为了封装和模块化,将一些只在本文件内部使用的辅助工具函数声明为 static,可以避免它们被其他文件误用,同时防止函数名冲突。
示例:
文件 utils.c
#include <stdio.h>
// 这是一个static函数,只能在utils.c内部调用
static void helper_function() {
printf("This is a helper function in utils.c.\n");
}
// 这是一个普通函数,可以被其他文件调用
void public_function() {
printf("This is a public function.\n");
helper_function(); // 在本文件内部可以调用static函数
}
文件 main.c
#include <stdio.h>
// 声明外部函数
void public_function();
// void helper_function(); // 如果取消注释并编译,会报 "undefined reference to `helper_function'" 错误
int main() {
public_function(); // 可以正常调用
// helper_function(); // 编译错误!无法访问
return 0;
}
总结表格
| 位置 | 修饰对象 | 作用域 | 生命周期 | 主要用途 |
|---|---|---|---|---|
| 函数内部 | 局部变量 | 仅限函数内部 | 整个程序运行期间 | 实现函数的“记忆”功能,保持状态 |
| 所有函数外部 | 全局变量 | 仅限当前源文件 | 整个程序运行期间 | 文件封装,避免全局变量名冲突 |
| 函数定义前 | 函数 | 仅限当前源文件 | 整个程序运行期间 | 文件封装,避免函数名冲突,实现模块化 |
static 在 C++ 中的扩展(了解即可)
在 C++ 中,static 关键字增加了新的用途,主要用于类:
- 静态成员变量:属于整个类,而不是某个对象,所有对象共享这个成员,必须在类外进行初始化。
- 静态成员函数:没有
this指针,只能访问类的静态成员变量,不能访问非静态成员,可以通过类名直接调用。
这些是 C++ 面向对象特性的一部分,与 C 语言中的 static 概念有所不同。
最佳实践
- 优先使用
static:如果一个函数或全局变量只在单个源文件中使用,就应该使用static关键字将其限制在该文件内,这可以极大地提高代码的模块化程度和可维护性,避免命名空间污染。 - 谨慎使用
static局部变量:虽然它们很有用,但在多线程环境下需要特别注意,因为它们在所有线程间共享状态,可能导致竞态条件,如果必须使用,需要确保访问是线程安全的。
