C 语言 static 完整讲解
2026/7/5 8:10:54 网站建设 项目流程

C 语言 static 完整讲解:分三大场景

static是存储修饰符,作用分全局变量、局部变量、函数三种场景,核心两个能力:

  1. 改变内存存放区域
  2. 限制作用域(文件隔离)

一、场景 1:修饰局部变量(函数内部)

1. 普通局部变量(无 static)

c

运行

void func(void) { int a = 0; // 存栈Stack,函数调用时创建,退出直接销毁 a++; printf("%d ", a); }

调用多次输出:1 1 1 1

  • 内存:栈;每次调用重新初始化为 0;函数结束销毁。

2. static 局部变量

c

运行

void func(void) { static int a = 0; // 存.bss/.data段,只初始化1次 a++; printf("%d ", a); }

调用多次输出:1 2 3 4

核心特性:
  1. 初始化仅执行 1 次:程序上电第一次进函数才赋值,后续调用保留上次值;
  2. 内存不在栈,在全局 RAM (.bss/.data):函数退出不会销毁,生命周期 = 整个程序运行;
  3. 作用域仅限当前函数:外部其他函数无法访问变量a
  4. 单片机优势:不占用栈空间,递归 / 循环不会栈溢出。

二、场景 2:修饰全局变量(函数外部)

1. 普通全局变量

c

运行

int g_val = 10; // 存.data段,整个工程所有.c文件都能extern访问

工程任意文件写extern int g_val;就能跨文件读写。

2. static 全局变量

c

运行

static int g_val = 10; // 存.data段,仅限当前.c文件使用
核心特性:
  1. 内存区域不变:仍在.data/.bss,程序全程存在;
  2. 文件作用域隔离:其他.c文件无法通过extern引用,杜绝跨文件重名冲突;
  3. 单片机项目规范:所有模块内部全局缓冲区(NTC 数组、缓存)全部加 static。

三、场景 3:修饰函数

1. 普通函数

c

运行

void TestNtc(void) { }

整个工程任意文件都能直接调用。

2. static 函数

c

运行

static void TestNtc(void) { }
核心特性:
  1. 仅限当前.c 文件调用,外部文件无法引用;
  2. 模块化隔离:只给本文件内部使用的工具函数,全部加 static,防止全局函数名泛滥;
  3. 链接时不会导出符号,固件体积轻微减小。

四、static 内存分布汇总表

表格

写法内存区域生命周期作用域
函数内int a栈 Stack函数单次调用仅当前函数
函数内static int a.bss/.data整个程序运行仅当前函数
文件外int g_a.bss/.data整个程序运行全工程所有文件
文件外static int g_a.bss/.data整个程序运行仅限当前.c 文件
普通函数void func()代码段 Flash程序运行全工程可调用
static void func()代码段 Flash程序运行仅限当前.c 文件

五、结合 NTC 单片机代码实战例子

例 1:static 局部变量(滤波计数,保留上次值)

c

运行

uint16_t Ntc_GetAdc(void) { static uint16_t filter_buf[8]; // 静态数组,不占栈,保存历史采样 static uint8_t idx = 0; uint16_t adc = ADC_Read(); filter_buf[idx++] = adc; idx %= 8; // 均值滤波计算... }

不加 static 的话,filter_buf在栈,数组大了直接栈溢出。

例 2:static 全局表(NTC 码值表,仅 ntc.c 内部使用)

c

运行

// ntc.c 文件内,其他文件无法访问这个表 #ifdef NTC_R_10K static const uint16_t ntc_code[] = {0x01C4,0x023B,...}; #elif defined(NTC_R_100K) static const uint16_t ntc_code[] = {0xXXXX,...}; #endif

例 3:static 内部工具函数(仅 ntc.c 内部调用)

c

运行

// 查表转换温度,外部文件不能调用 static int Ntc_CodeToTemp(uint16_t adc) { // 二分查表逻辑 } // 对外提供的接口,不加static,其他文件可调用 int Ntc_GetTemp(void) { uint16_t adc = Ntc_ReadAdc(); return Ntc_CodeToTemp(adc); }

六、高频易错点

  1. static const常量:
    • 全局static const:存.rodata只读 Flash,不占 RAM;
    • 函数内static const:同样存在只读区,不会每次进函数重复分配。
  2. static 局部变量初始化只一次:

    c

    运行

    static int a = 10; // 仅上电执行一次 a = 10; // 每次调用都会重新赋值,覆盖记忆值
  3. 栈溢出解决方案:大数组、缓冲区全部用static修饰,转移到全局 RAM,不占用栈。
  4. 模块化规范:
    • 模块私有变量 / 工具函数:全部加static
    • 对外接口、跨文件变量:不加 static。

总结

  1. 函数内 static 变量:保值、不占栈、生命周期全局
  2. 全局 static 变量 /static 函数:锁死在当前文件,外部不可访问

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询