嵌入式开发中为啥常用do{}while(0)进行宏定义
do{}while(0)宏定义方式广泛应用于Linux内核源码、FreeRTOS、uCOS-II、ARM内核、STM32......。
主要基于以下技术原因和优势:
场景1:语法歧义或错误、逻辑错误问题
#define EXTIE1() {EXTI_FTSR &= 0xFF00; EXTI_BTSR &= 0xFF0F;}
#define EXTIE2() {EXTI_FTSR &= 0xFF00; EXTI_BTSR &= 0xFF0F}
#define EXTIE3() EXTI_FTSR &= 0xFF00; EXTI_BTSR &= 0xFF0Fif (condition)EXTIE1(x); // 这里多个分号
if elseEXTIE2(); // 这里有分号
if elseEXTIE3(); // 这里有分号
elseSomething(); // 这里有分号
展开
if (condition){EXTI_FTSR &= 0xFF00; EXTI_BTSR &= 0xFF0F;}; // 这里有两个分号!语法歧义或错误
if else{EXTI_FTSR &= 0xFF00; EXTI_BTSR &= 0xFF0F}; // 这里有个分号!语法歧义或错误
if elseEXTI_FTSR &= 0xFF00; EXTI_BTSR &= 0xFF0F; // 逻辑错误
elseSomething(); // 这里有分号
场景2:编码风格不一致导致的维护问题
#define EXTIE1() {EXTI_FTSR &= 0xFF00; EXTI_BTSR &= 0xFF0F;}
#define EXTIE2() EXTI_FTSR &= 0xFF00;
#define EXTIE3() EXTI_BTSR &= 0xFF0F
if (condition)EXTIE1(x) // 这里无分号!与函数语法不一致
if elseEXTIE2() // 这里有个分号!
if elseEXTIE3(); // 这里有个分号!若这个宏是其他合作者定义的,与团队语法不一致
elseSomething(); // 这里有分号
展开
if (condition){EXTI_FTSR &= 0xFF00; EXTI_BTSR &= 0xFF0F;} // 这里无分号!
if elseEXTI_FTSR &= 0xFF00; // 这里有个分号!
if elseEXTI_BTSR &= 0xFF0F; // 这里有个分号!
elseSomething(); // 这里有分号
场景3:支持局部变量定义
#define SWAP(a, b) {tmp = a, a = b, b = tmp;} // 有语法错误,除非tmp在外面定义变量
#define SWAP(a, b) do{int tmp = a, a = b, b = tmp;}while(0) // 正确,不用单独在外部定义临时变量
场景4:避免空宏的编译警告
#define MACRO_DEF1() // 空宏定义可能引发编译器警告
#define MACRO_DEF2() do{}while(0) // 空宏定义能通过编译,无警告
场景5: 行为一致,不产生额外代码
优化友好:现代编译器会优化掉 while(0),不会产生任何额外代码
作用域清晰:在宏内部定义的变量不会泄露到外部
行业标准:被广泛认可的最佳实践,无论在哪里使用,行为都是一致的
