C语言中的static关键字是一个用途非常广泛的关键字,它可以根据修饰对象的不同,产生不同的效果,主要可以分为修饰局部变量、修饰全局变量、修饰函数三大类场景,下面我们逐一进行讲解。

一、static修饰局部变量
当static用来修饰函数内部的局部变量时,这个变量就被称为局部静态变量。普通的局部变量存储在栈区,函数调用结束后就会被销毁,而局部静态变量存储在静态存储区,函数调用结束后不会被销毁,下次调用函数时,这个变量会保留上一次的值。
我们来看一个对比示例,首先是普通局部变量的代码:
#include <stdio.h>
void normal_func() {
int num = 0; // 普通局部变量
num++;
printf("普通局部变量num的值:%dn", num);
}
int main() {
normal_func();
normal_func();
normal_func();
return 0;
}
这段代码的运行结果是三次都输出1,因为每次调用normal_func函数时,num都会被重新初始化为0,然后加1输出。
接下来我们把num改成用static修饰的局部静态变量:
#include <stdio.h>
void static_func() {
static int num = 0; // 局部静态变量
num++;
printf("局部静态变量num的值:%dn", num);
}
int main() {
static_func();
static_func();
static_func();
return 0;
}
这段代码的运行结果是依次输出1、2、3,因为num存储在静态区,第一次初始化为0之后,后续调用函数不会再重新初始化,而是保留上一次的值继续累加。
需要注意,局部静态变量虽然生命周期变长了,但是它的作用域仍然只在定义它的函数内部,其他函数无法直接访问这个变量。
二、static修饰全局变量
全局变量本身存储在静态存储区,生命周期是整个程序运行期间,但是普通的全局变量具有外部链接属性,也就是其他源文件可以通过extern关键字声明后使用这个全局变量。当用static修饰全局变量时,这个全局变量就变成了全局静态变量,它的外部链接属性会被取消,只能在当前定义它的源文件中使用,其他源文件无法访问。
我们来看一个示例,假设我们有两个源文件,第一个是test.c:
#include <stdio.h>
static int global_num = 10; // 全局静态变量
void print_num() {
printf("global_num的值:%dn", global_num);
}
第二个是main.c:
#include <stdio.h>
extern int global_num; // 尝试声明test.c中的global_num
int main() {
printf("global_num的值:%dn", global_num);
return 0;
}
如果直接编译这两个文件,会提示找不到global_num的定义,因为static修饰的全局变量只能在test.c中使用,main.c无法通过extern访问。如果我们把test.c中global_num的static修饰去掉,那么main.c就可以正常访问这个全局变量了。
这种特性可以用来避免不同源文件之间的全局变量命名冲突,把不需要被其他文件使用的全局变量用static修饰,就可以限制它的作用域,提高代码的模块化程度。
三、static修饰函数
和全局变量类似,普通的C语言函数默认具有外部链接属性,其他源文件只要声明了函数原型就可以调用。当用static修饰函数时,这个函数就变成了静态函数,它的外部链接属性被取消,只能在当前定义它的源文件中被调用,其他源文件无法调用。
我们来看示例,首先是test.c:
#include <stdio.h>
static void static_func() { // 静态函数
printf("这是test.c中的静态函数n");
}
void public_func() {
printf("这是test.c中的普通函数n");
static_func(); // 当前文件内可以调用静态函数
}
然后是main.c:
#include <stdio.h>
void public_func(); // 声明test.c中的普通函数
// static void static_func(); // 即使声明也无法调用静态函数
int main() {
public_func(); // 可以正常调用
// static_func(); // 编译会报错,无法调用其他文件的静态函数
return 0;
}
静态函数的作用和全局静态变量类似,可以用来隐藏函数实现,避免其他文件误调用,同时也可以避免不同源文件中函数命名冲突的问题,让函数的封装性更好。
四、static使用的注意事项
- 局部静态变量只能在定义的时候初始化一次,之后调用函数不会再执行初始化操作,如果没有显式初始化,会被自动初始化为0(普通局部变量不初始化是随机值)。
- static修饰的全局变量和函数,作用域仅限于当前源文件,无法被其他源文件通过extern访问,这个特性和C++中的static用法有所区别,需要注意区分。
- 不要在头文件中定义static修饰的全局变量或函数,因为头文件会被多个源文件包含,每个包含该头文件的源文件都会拥有自己独立的static变量或函数副本,不仅会造成代码冗余,还可能引发逻辑错误。
五、总结
static关键字在C语言中的核心作用是改变变量的存储周期或者限制标识符的作用域:修饰局部变量时延长变量的生命周期,修饰全局变量和函数时限制它们的作用域为当前源文件。合理使用static可以让代码的模块化程度更高,减少命名冲突,在实际编程中是非常常用的一个关键字。