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

相关推荐
fffzd14 小时前
STM32:IIC与温湿度传感器(轮询模式)
stm32·单片机·嵌入式硬件·iic·通信·嵌入式软件·i2c
都在酒里2 天前
FreeRTOS 综合实战:串口命令控制 LED 闪烁模式与系统监控
stm32·单片机·嵌入式硬件·嵌入式·rtos·嵌入式软件
都在酒里3 天前
FreeRTOS 手动移植教程(七):软件定时器 —— 不占硬件 Timer 的定时回调
stm32·单片机·嵌入式·rtos·嵌入式软件
都在酒里3 天前
FreeRTOS 手动移植教程(八):中断管理 —— 优先级、临界区与任务通知
stm32·单片机·嵌入式·rtos·嵌入式软件
都在酒里4 天前
FreeRTOS 手动移植教程(五):信号量 —— 任务同步与中断通知的优雅解决方案
stm32·单片机·rtos·嵌入式软件
Plankton_Li11 天前
嵌入式国密加密:STM32L4 + MIRACL 库实现 SM2 加解密
stm32·单片机·嵌入式软件
smalming14 天前
【产品开发】空气波按摩器的一些控制逻辑
嵌入式硬件·嵌入式软件
螺丝钉的扭矩一瞬间产生高能蛋白1 个月前
QT的C++接口基础用法
c++·qt·嵌入式软件·嵌入式linux·linux应用
CC城子1 个月前
嵌入式Linux宕机问题GDB调试(一)
gdb·嵌入式软件
码农小韩1 个月前
QT学习记录(三)——C++学习基础(三)
开发语言·c++·qt·学习·算法·嵌入式软件