摘要:条件编译(#if/#endif)是嵌入式开发中的重要技术,可实现代码选择性编译。主要应用场景包括:1)快速注释大段代码(#if 0);2)灵活切换不同硬件接口(如SPI/I2C);3)调试日志分级管理(通过DEBUG_LEVEL控制)。相比普通if语句,条件编译能在预处理阶段完全移除不需要的代码,有效节省存储空间并提升运行效率。这种技术特别适合资源受限的嵌入式系统开发。

目录

一、使用 #if 0 快速注释大段代码

二、更改驱动方式

三、串口打印调试


在嵌入式开发中,#if#endif 被称为条件编译(Conditional Compilation)。它的本质是:给编译器下达“选择性过滤”的指令

一、使用 #if 0 快速注释大段代码

当你想暂时停用一大段代码进行排查时,可以不用 /* ... */,因为如果代码内部已经有了注释,会导致嵌套错误

#if 0
    // 这里的代码完全被编译器忽略
    // 即使里面有 /* 这种注释 */ 也不会报错
    void Old_Function() {
        Do_Something();
    }
#endif

想恢复时,只需要把 0 改成 1 即可。

二、更改驱动方式

假设你正在写一个 LCD 显示屏驱动,但LCD 显示屏有两个版本:版本 A 使用 SPI 接口,版本 B 使用 I2C 接口。

#define INTERFACE_TYPE_SPI 1
#define INTERFACE_TYPE_I2C 2

#define CURRENT_INTERFACE INTERFACE_TYPE_SPI // 切换这个宏即可改变整个项目的编译逻辑

// 在驱动文件 (display.c) 中
void Display_Init() {
    #if (CURRENT_INTERFACE == INTERFACE_TYPE_SPI)
        // 这里的代码会被编译
        SPI_Init();
        GPIO_SetMode(PORT_A, PIN_1, ALTERNATE_SPI);
    #elif (CURRENT_INTERFACE == INTERFACE_TYPE_I2C)
        // 如果上面条件满足,这段代码在预处理阶段就会被“删掉”
        // 编译器压根看不见它,就像它从未存在过一样
        I2C_Init();
        GPIO_SetMode(PORT_B, PIN_2, ALTERNATE_I2C);
    #else
        #error "未指定的接口类型!" // 报错提醒,防止漏配
    #endif
}

如果用普通的 if,即使用 SPI 模式,I2C 的初始化代码依然会占用单片机的 Flash 空间

三、串口打印调试

在开发时,我们需要大量的串口打印来排查错误,但打印字符串是非常消耗 CPU 时间和存储空间的

#define DEBUG_LEVEL 2  // 0: 关闭, 1: 错误, 2: 详情

void Process_Data(uint8_t *data) {
    #if (DEBUG_LEVEL >= 1)
        if (data == NULL) Log_Error("Null Pointer!");
    #endif

    #if (DEBUG_LEVEL >= 2)
        Log_Info("Data received successfully");
    #endif

    // 核心业务代码
    Do_Something(data);
}

在项目调试阶段,将DEBUG_LEVEL设置为2以启用所有日志记录功能。

项目完成后,将DEBUG_LEVEL调整为0。此时编译器在预处理阶段会优化代码,Process_Data函数中仅保留Do_Something(data)这一行有效代码。这样不仅能显著减小固件体积,还能提升程序的运行效率。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐