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

相关推荐
阿泽·黑核13 天前
表驱动 + 回调分发:大规模按键模块的工程实践
c语言·嵌入式软件·vibe coding·trae solo
咖喱年糕16 天前
KEIL5 编译错误解决:MDK 5.37 及以上版本添加 AC5(ARM Compiler 5)编译器
arm开发·单片机·keil·嵌入式软件·ac5
都在酒里16 天前
【极致低延时】香橙派部署 MediaMTX 实现 WebRTC 推流,延时仅 500-800ms,比局域网 ffmpeg 拉流快近 10 倍!(附踩坑全记录)
linux·arm开发·ffmpeg·webrtc·orangepi·嵌入式软件
fffzd17 天前
STM32:OLED原理
stm32·单片机·嵌入式硬件·iic·oled·嵌入式软件
fffzd20 天前
STM32:时钟树与时钟源
单片机·嵌入式硬件·嵌入式软件·时钟树·时钟源
fffzd21 天前
STM32:IIC与温湿度传感器(轮询模式)
stm32·单片机·嵌入式硬件·iic·通信·嵌入式软件·i2c
都在酒里22 天前
FreeRTOS 综合实战:串口命令控制 LED 闪烁模式与系统监控
stm32·单片机·嵌入式硬件·嵌入式·rtos·嵌入式软件
都在酒里23 天前
FreeRTOS 手动移植教程(七):软件定时器 —— 不占硬件 Timer 的定时回调
stm32·单片机·嵌入式·rtos·嵌入式软件
都在酒里23 天前
FreeRTOS 手动移植教程(八):中断管理 —— 优先级、临界区与任务通知
stm32·单片机·嵌入式·rtos·嵌入式软件
都在酒里24 天前
FreeRTOS 手动移植教程(五):信号量 —— 任务同步与中断通知的优雅解决方案
stm32·单片机·rtos·嵌入式软件