#ifndef FLOW_EXT #define FLOW_EXT extern

.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项目中很常见!

相关推荐
怀民民民18 小时前
嵌入式软件学习路线与项目实践记录:STM32、FreeRTOS、Linux 与 OpenMV
stm32·freertos·嵌入式软件·嵌入式linux·openmv
youcans_5 天前
【嵌入式软件AI编程】12. Claude Code的基本操作
stm32·单片机·ai编程·嵌入式软件·claude code
youcans_6 天前
【嵌入式软件AI编程】09. 使用VS Code调试STM32程序
stm32·mcu·ai编程·嵌入式软件·claude code
youcans_8 天前
【嵌入式软件AI编程】08. 第一个STM32工程
stm32·单片机·ai编程·嵌入式软件·claude code
老猿讲编程11 天前
【Eclipse OpenSOVD学习之十】客户端 SDK
学习·eclipse·嵌入式软件·车载·sovd
泛联新安12 天前
FPGA功能仿真:VShark正式亮相,换仿真器不用换习惯
fpga开发·编译·仿真·嵌入式软件·代码漏洞扫描
老猿讲编程12 天前
【Eclipse OpenSOVD学习之六】 数据访问层(DataProvider)
学习·eclipse·嵌入式软件·车载·sovd
泛联新安12 天前
FPGA仿真加速:AccEmu正式亮相,一周的回归,一天跑完
机器学习·fpga开发·数据挖掘·回归·自动化·嵌入式软件·代码漏洞扫描
花 满 楼13 天前
5777M的eMIOS 封波(ODIS)功能实现:一个通道输入沿触发,冻结另一个通道 PWM 输出
mcu·嵌入式软件·emios
youcans_13 天前
【嵌入式软件AI编程】03. STM32 VS Code 开发环境与工具链
stm32·单片机·ai编程·嵌入式软件·claude code