do while 在宏定义中的作用
2021-12-10 本文已影响0人
yxibng
看CocoaLumberjack 源码, 对宏定义的语句用do while 来包裹,探究一下这么做的原因
#define NSLogDebug(frmt, ...) do{ if(DD_DEBUG) NSLog((frmt), ##__VA_ARGS__); } while(0)
使宏调用表现得和正常代码一样
在c/c++/oc 中,正常的代码以;
结尾, 如果看到一个不以;
结尾的代码,会觉得很奇怪,为啥没报错?
doSomething(1) ;
DO_SOMETHING_ELSE(2) // <== Hey? What's this?
doSomethingElseAgain(3) ;
用户期待在代码结尾缺少;
的时候,编译器能正常报错。
所以理想的宏调用应该是, 用户自己在宏语句后添加;
doSomething(1) ;
DO_SOMETHING_ELSE(2);
doSomethingElseAgain(3) ;
产出合法代码
单条宏包含多个语句,在没有{}
的if
语句被调用,导致if 语句的范围覆盖出问题
#define MY_MACRO(x) f(x) ; g(x)
if(bIsOk)
f(42) ; g(42) ; // was MY_MACRO(42) ;
如果用{}
来包裹, 多了一个;
#define MY_MACRO(x) { f(x) ; g(x) ; }
if(bIsOk)
{ f(42) ; g(42) ; } ; // was MY_MACRO(42) ;
如果if
后还有else
#define MY_MACRO(x) { f(x) ; g(x) ; }
if (true)
MY_MACRO(42);
else
NSLog(@"xxx");
宏展开后 else
前面多了一个;
语法错误
if (bIsOk)
{ f(42) ; g(42) ; };
else
NSLog(@"xxx");
合法化代码,作用域保护
看下面的宏定义
#define MY_MACRO(x) int i = x + 1 ; f(i) ;
在以下函数调用中出问题
void doSomething()
{
int i = 25 ;
MY_MACRO(32) ;
}
上面的代码展开后, 编译出错
void doSomething()
{
int i = 25 ;
int i = 32 + 1 ; f(i) ; ; // was MY_MACRO(32) ;
}
使用do while
来包裹
do
{
// code
}
while(false) ;
好处
- 会创建一个作用域来包裹代码块
- 结尾需要一个
;
- 编译器会对条件确定为
false
情况的do while
在编译时优化
#define MY_MACRO(x) \
do \
{ \
const int i = x + 1 ; \
f(i) ; g(i) ; \
} \
while(false)
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
MY_MACRO(42) ;
// Etc.
}
展开后
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
do
{
const int i = 42 + 1 ; // was MY_MACRO(42) ;
f(i) ; g(i) ;
}
while(false) ;
// Etc.
}
优化后
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
{
f(43) ; g(43) ;
}
// Etc.
}
参考:
Why use apparently meaningless do-while and if-else statements in macros?
内联函数 —— C 中关键字 inline 用法解析