🔧 AI 知识库

嵌入式 C 语言必须吃透的 6 类关键字

原文链接

嵌入式 C 语言必须吃透的 6 类关键字

原文链接:https://mp.weixin.qq.com/s/c9SMHzaLsAGIYZWmDFDxAg 作者:一枚嵌入式码农 发布时间:2026年7月9日

摘要

嵌入式开发中 6 类关键字的深度解析,每类结合真实硬件场景讲原理和坑:volatile 解决编译器优化导致的中断变量不同步、static 是 C 语言唯一的封装手段、const 把数据从 RAM 赶回 Flash 省内存、extern 的声明规范、struct/union 对接硬件协议、enum/typedef/inline 提升可读性。

主要内容

1. volatile — 嵌入式的第一关键字

编译器优化会缓存变量值到寄存器,导致中断修改了内存但 CPU 读的还是旧值。三类必须加 volatile 的数据:

  • 中断和主循环共享的变量
  • 内存映射的外设寄存器
  • RTOS 下多任务无锁共享的变量

volatile 不保证原子性,32 位变量自增在 8 位机上仍然是多指令,该关中断还是要关。

2. static — C 语言唯一的封装手段

位置作用
函数内局部变量生命周期延至整个程序,值保留在 .data/.bss
文件内全局变量作用域限制在当前 .c,其他文件不可见
函数限制在本文件内可见

模块化写法:static 变量 + static 内部函数,只暴露接口函数。static 函数不可重入,主循环和中断同时调用会互相踩。

3. const — 省 RAM 的关键

MCU 通常 Flash 大 RAM 小,不加 const 的全局数组进 RAM,加 const 进 .rodata 段(Flash)。字库、正弦表、CRC 表、默认参数表一定要加 const。

const 的另外两个用途:

  • 函数参数声明 const 指针,约定"只读不改"
  • 与 volatile 组合修饰只读寄存器:*(volatile const uint32_t *)addr

4. extern — 声明不是定义

正确做法:定义放 .c,声明放 .h。不要散落在各个 .c 文件里随手 extern。

典型翻车现场:

/* a.c 定义数组 */
uint8_t g_buf[128];
/* b.c 声明成指针 */
extern uint8_t *g_buf;  /* 编译链接通过,运行跑飞 */

5. struct / union — 对接硬件协议

  • 位域:描述寄存器,mode : 2 比掩码移位直观,但位域顺序实现定义,跨平台协议慎重
  • union:同一内存多解释,float ↔ bytes 收发无需移位拼接
  • 注意事项:字节序、结构体对齐(#pragma pack / __attribute__((packed))

6. enum / typedef / inline — 可读性三件套

  • enum:状态机和错误码,编译期类型检查,调试器直接显示状态名
  • typedef:定宽类型(uint8_t 等),函数指针别名
  • inline:替代函数式宏,保留类型检查和调试能力

原文关键段落

如果只允许记住一个关键字,那一定是 volatile。它告诉编译器,这个变量随时可能被你看不见的东西修改,每次使用都必须老老实实从内存里读。

C 语言没有 class,没有 private,static 就是它唯一的访问控制手段。

一个 12KB 的字模数组因为漏了 const,白白吃掉三分之一的 RAM,项目后期内存告急,查了半天才发现根源在这。