C/C++ 宏中 `do { ... } while (0)` 的“零次循环”技巧

1. 问题现象

C/C++ 宏只是简单的文本替换,若宏体包含多条语句,替换后极易出现以下两类错误:

  1. else 悬空

    cpp 复制代码
    #define FOO(x)  stmt1; stmt2;
    if (cond)
        FOO(x);   // 只有 stmt1 受 if 控制
    else
        bar();
  2. 花括号与分号不匹配

    cpp 复制代码
    #define FOO(x) { stmt1; stmt2; }
    if (cond)
        FOO(x);   // 展开后多了一个分号,编译错误
    else
        bar();

2. 解决方案:do { ... } while (0)

把宏体包装在 单次执行的 do-while 循环 中:

cpp 复制代码
#define FOO(x) \
    do { stmt1; stmt2; } while (0)
  • 语义 :循环体只执行一次,与 if/else、for、while 等结构无缝衔接。
  • 语法 :do { ... } while (0); 末尾自带分号,用户正常写 FOO(x); 即可通过编译。

3. 正确展开示例

cpp 复制代码
if (cond)
    FOO(x);
else
    bar();

展开后:

cpp 复制代码
if (cond)
    do { stmt1; stmt2; } while (0);
else
    bar();
  • 结构完整,无 else 悬空。
  • 分号恰好被 while (0); 吸收,无多余符号。

4. 为什么不能仅用大括号

cpp 复制代码
#define FOO(x) { stmt1; stmt2; }
  • 替换后:

    cpp 复制代码
    if (cond)
        { stmt1; stmt2; };   // 多余的分号导致语法错误
    else
        bar();
  • 大括号本身不带分号,无法消化用户写下的分号。


5. 使用要点

  1. 宏体含多条语句、内部变量定义或需要"单语句"语义时,务必 使用 do { ... } while (0)。
  2. 对于只含一条表达式的宏,可省略此技巧,但保持一致性亦可保留。
  3. 现代 C++ 推荐用 inline 函数或模板替代宏;若必须用宏,则遵循此范式。

6. 结论

do { ... } while (0) 是一个 零成本、零副作用 的惯用法,确保宏在任何上下文中表现如一条普通语句。

相关推荐
架构技术专栏16 分钟前
为什么 AI 公司都想做Personal Agent ?
后端
用户7610160884738 分钟前
黑马RabbitMQ 从入门到可靠性:收发、持久化、死信延迟一篇打通
后端
Bazingga1 小时前
Transformer与自注意力机制:一台"全员检索"机器的说明书
人工智能·后端
星辰云-1 小时前
# 基于Spring Boot的德州特产扒鸡商城系统(毕设|源码|论文|演示视频)
spring boot·后端·课程设计
武子康1 小时前
同为7/8,错误样本却不同:Agent Grader 分歧复算
人工智能·后端·agent
茉莉玫瑰花茶1 小时前
GO [ 内存与变量逃逸分析 ]
开发语言·后端·golang
星辰云-1 小时前
基于Spring Boot的旅游景点票务系统的设计与实现(毕设项目,附完整源码)
spring boot·后端·课程设计
Rain的Java大神之路2 小时前
百万并发直播弹幕系统设计全解:看懂了扇出,你就看懂了高并发的八成
java·后端·面试
山间小僧2 小时前
Agent Memory(三)团队记忆:以 TencentDB Agent Memory 为例
后端·agent
十年Java程序媛2 小时前
JVM 基础与 GC 垃圾回收详解|可达性分析、分代模型、垃圾收集器、STW
java·开发语言·jvm·spring boot·后端·面试