C++中宏用do{} while(false)的原因( 以Sophus 为例)

507 阅读1分钟

作者: 边城量子 ( shihezichen@live.cn )

背景

在阅读C++库的代码过程中,经常会遇到把一个宏定义用 do{ }while(false) 包括起来的情况, 例如 Sophus 库中 common.hpp 就有如下代码:

common.hpp:

#define SOPHUS_ENSURE(expr, ...)                                              \
  do {                                                                        \
    if (!(expr)) {                                                            \
      SOPHUS_DEDAULT_ENSURE_FAILURE_IMPL(SOPHUS_FUNCTION, __FILE__, __LINE__, \
                                         ##__VA_ARGS__);                      \
    }                                                                         \
  } while (false)

为什么要把宏的定义包裹在 do { } while(false) 块中呢?

分析

主要是为了封闭代码,让宏定义被封闭在 do {} while(false) 中, 这样宏用在其他的程序结构中(比如 if ... else ... )就不容易出错。

在 C/C++ 中, 定义一个宏有很多种方法:

#define SET_MACRO_1()  var1 = 0; var2 = 0; 
#define SET_MACRO_2()  { var1 = 0; var2 = 0; }
#define SET_MACRO_3()  do { var1 = 0; var2 = 0; } while(false)

其中1、2两种用在 if/else 结构中就会出错,以第1种宏定义为例,放入如下的代码中:

if(ret) 
   SET_MACRO_1();
else
{
   ...
}

宏展开后变为:

if(ret) 
   var1 = 0; var2 = 0; ;
else
{
   ...
}

可以发现多了一个分号, 导致后面的 else 无法找到匹配的 if; 第2中宏定义也有类似的问题。 使用第3种 do { }while(false) 则没有这种问题,如下:

if(ret)
   do { var1 = 0; var2 = 0; } while(false);
else
{
   ...
}