.c 文件里面:#define FLOW_EXT, .h文件里面:#ifndef FLOW_EXT #define FLOW_EXT extern #endif FLOW_EXT u16 t_boundary_1s; 怎么理解?
1. 在 .c 文件中
c
// source.c #define FLOW_EXT // 定义 FLOW_EXT 宏(值为空) #include "header.h" // 此时头文件中的代码会这样展开...
2. 在 .h 文件中
h
// header.h #ifndef FLOW_EXT // 检查 FLOW_EXT 是否未定义 #define FLOW_EXT extern // 如果未定义,定义为 "extern" #endif FLOW_EXT u16 t_boundary_1s; // 使用 FLOW_EXT 修饰变量
关键:展开结果不同
情况1:在定义了FLOW_EXT的 .c 文件中
c
// FLOW_EXT 已定义(值为空),所以跳过 #define // 直接执行:FLOW_EXT u16 t_boundary_1s; // 展开为:(空) u16 t_boundary_1s; // 最终:u16 t_boundary_1s; ← 这是变量定义(分配内存)
情况2:在未定义FLOW_EXT的其他 .c 文件中
c
// FLOW_EXT 未定义,执行 #define FLOW_EXT extern // 然后:FLOW_EXT u16 t_boundary_1s; // 展开为:extern u16 t_boundary_1s; ← 这是变量声明(不分配内存)
完整示例
global.h
h
#ifndef GLOBAL_H #define GLOBAL_H typedef unsigned short u16; #ifndef FLOW_EXT #define FLOW_EXT extern #endif FLOW_EXT u16 t_boundary_1s; // 魔法在这里! #endif
main.c(定义变量的文件)
c
#define FLOW_EXT // 关键:先定义这个宏 #include "global.h" // 经过预处理后,上面那行变成: // u16 t_boundary_1s; ← 实际定义变量,分配内存 void main() { t_boundary_1s = 100; // 可以直接使用 }other.c(使用变量的文件)
c
// 不定义 FLOW_EXT #include "global.h" // 经过预处理后,上面那行变成: // extern u16 t_boundary_1s; ← 只是声明,不分配内存 void func() { t_boundary_1s = 200; // 引用 main.c 中定义的变量 }核心理解
| 文件 | FLOW_EXT 状态 | 宏展开 | 实际代码 | 作用 |
|---|---|---|---|---|
| main.c | #define FLOW_EXT | 空 | u16 t_boundary_1s; | 定义(分配内存) |
| other.c | 未定义 | extern | extern u16 t_boundary_1s; | 声明(引用外部) |
为什么这样设计?
传统方式需要维护两处:
h
// 需要在头文件和源文件分别声明 extern u16 t_boundary_1s; // .h文件 u16 t_boundary_1s; // 某个.c文件
这种技巧的优势:
✅单一维护点:只需在头文件中写一次变量声明
✅自动区分:通过
#define FLOW_EXT控制是定义还是声明✅防止重复定义:只有一个文件会实际定义变量
✅代码清晰:明确哪个文件是变量的"所有者"
这是一种优雅的全局变量管理技巧,在嵌入式系统和大型C项目中很常见!