C 语言 static的用法

C 语言 static的用法

static分三大使用场景:局部变量、全局变量、函数,作用核心只有两点:

  1. 修改存储周期:变量生命周期延长至整个程序运行期间
  2. 修改作用域(可见性):限制作用域仅当前.c文件内部

一、static 修饰局部变量(函数内部)

1. 普通局部变量 vs static 局部变量

void test() { int a = 0; // 普通局部变量:栈存储,函数调用结束销毁 static int b = 0; // static局部变量:静态存储区,程序结束才销毁 a++; b++; printf("a=%d, b=%d\n", a, b); } int main() { test(); // a=1, b=1 test(); // a=1, b=2 test(); // a=1, b=3 return 0; }

2. 核心特性

  1. 初始化只执行 1 次static int b=0;仅程序启动时初始化一次,后续重复调用函数不会重新赋值;普通变量每次进函数都重新创建赋值。
  2. 存储位置不同
    • 普通局部:栈(stack),函数退出释放,每次调用重新分配
    • static 局部:静态全局区(data 段),全局生命周期
  3. 作用域不变依然只能在当前函数内访问,外部无法读取 / 修改。
  4. 默认自动初始化为 0不写赋值static int x;,x 初始就是 0;普通局部变量不初始化是随机垃圾值。

3. 典型用途

  • 函数计数、记录上次调用状态、只初始化一次的缓存数据
// 只打印一次提示 void log_once() { static int flag = 0; if (!flag) { printf("程序启动日志\n"); flag = 1; } }

二、static 修饰全局变量(函数外部)

1. 不加 static 全局变量

// file1.c int num = 10; // 全局变量,外部文件可跨文件访问 // file2.c extern int num; // 声明后就能使用file1的num

2. 加 static 全局变量

// file1.c static int num = 10;
  • 作用域限制:文件内私有仅当前.c文件可见,其他.c文件用extern也无法访问、不能重定义同名变量。
  • 存储周期不变依旧存静态区,程序全程存在,默认初始 0。

3. 作用

多文件开发时,隔离文件私有全局变量,避免全局命名冲突

三、static 修饰函数(函数定义前)

// file1.c static void func() { printf("私有函数\n"); }
  1. 作用域限制:函数仅当前.c文件可用,外部文件无法调用,不能用extern声明。
  2. 用途:封装模块内部工具函数,对外隐藏实现,减少命名污染。
  3. 对比无 static 函数:普通函数是全局可见,全工程可调用。

四、static 三大场景对比总结表

修饰对象存储位置生命周期作用域初始化规则
普通局部变量栈 stack单次函数调用当前函数每次调用重新初始化,默认随机值
static 局部变量静态数据段整个程序运行当前函数仅初始化 1 次,默认 0
普通全局变量静态数据段整个程序运行整个工程所有文件程序启动初始化,默认 0
static 全局变量静态数据段整个程序运行仅当前.c 文件程序启动初始化,默认 0
普通函数代码段程序运行全工程可调用-
static 函数代码段程序运行仅当前.c 文件可调用-

五、常见易错点

1.static 局部变量的初始化不能放表达式里动态赋值

void test() { int n = 5; static int x = n; // 编译报错!static初始化必须是常量 }

2. static 变量不支持递归重置状态 递归调用同一个函数,static 变量会持续累加,不会每次递归清零。

3. static 不能修饰函数形参

void func(static int a) // 语法错误,不允许

4. 头文件定义 static 变量会出现多副本 如果在.hstatic int x;,每个包含该头文件的.c都会生成一份独立 x,互不干扰。

六、综合实战示例

示例 1:static 局部实现计数器

#include <stdio.h> int get_cnt() { static int cnt = 0; cnt++; return cnt; } int main() { printf("%d\n", get_cnt()); //1 printf("%d\n", get_cnt()); //2 printf("%d\n", get_cnt()); //3 return 0; }

示例 2:多文件 static 隔离(模块化)

// math.c static int cache = 0; // 仅math.c内部可用 static void reset() { // 内部私有函数 cache = 0; } int add(int a, int b) { cache = a + b; return cache; } // main.c #include <stdio.h> extern int add(int a, int b); int main() { printf("%d", add(2,3)); // cache、reset() 这里无法访问,编译报错 return 0; }

七、总结

  1. 函数内 static 变量:长存,只初始化一次,函数内独享;
  2. 文件外 static 全局 / 函数:私有,仅限当前.c,外部看不见。