几种解释。第一个是通用的,第二个特定于具有参数的C预处理器宏:
流量控制
我已经看到了在纯C代码中使用的代码。基本上,它是goto的安全版本,因为您可以脱离它,并且所有内存都可以正确清理。
为什么会有类似的东西goto
好?好吧,如果你有代码,其中几乎每行可以返回一个错误,但你需要作出反应,他们都以同样的方式(例如,通过移交这个错误给调用者清理后),它通常是更具可读性,以避免if( error ) { /* cleanup and error string generation and return here */ }
为它避免了重复的清理代码。
但是,在C ++中,正是出于这个目的,有例外+ RAII,所以我认为它是不好的编码风格。
分号检查
如果在函数调用宏之后忘记了分号,则参数可能会以不希望的方式收缩并编译为有效的语法。想象一下宏
#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");
那是偶然地称为
if( foo )
PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
doSomethingElse();
在“其他”会被认为是与相关的gDebugModeOn
,所以,当foo
是false
时,完全相反的意图是什么会发生。
提供临时变量的范围。
由于do / while带有花括号,因此临时变量具有明确定义的范围,它们无法转义。
避免“可能不需要的分号”警告
某些宏仅在调试版本中被激活。您可以像这样定义它们:
#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n)
#endif
现在,如果您在条件内部的发布版本中使用此代码,它将编译为
if( foo )
;
许多编译器将此视为与
if( foo );
这通常是偶然写的。因此,您会收到警告。do {} while(false)将其从编译器中隐藏,并被编译器接受,以表明您确实不想在此处执行任何操作。
避免被条件捕获
上例中的宏:
if( foo )
DBG_PRINT_NUM(42)
doSomething();
现在,在调试版本中,由于我们习惯性地也包括了分号,因此编译就可以了。但是,在发布版本中,它突然变成:
if( foo )
doSomething();
或更清晰的格式
if( foo )
doSomething();
这根本不是预期的。在宏周围添加do {...} while(false)会将丢失的分号转换为编译错误。
这对OP意味着什么?
通常,您希望使用C ++中的异常进行错误处理,并使用模板而不是宏。但是,在极少数情况下,您仍然需要宏(例如,使用令牌粘贴生成类名时)或仅限于纯C语言,这是一种有用的模式。