工作中,我写了一个宏定义,它的第一个版本大概是这样的。
#define MSG_TRACE(msg,transport,isReceived) \
do { \
if (isMessageTraceOn()) { \
msgTrace((msg),(transport),(isReceived)); \
} \
} while (0)
我之所以用宏定义是为了每次调用msgTrace的时候,不需要写if语句判断。函数msgTrace的代码我是不能修改的,所以我也不能把if语句移到msgTrace里面。
这段代码我交给外国同事检视。他提的建议之一是我的那个do while语句用得没有必要。我为什么写do while呢,因为我看到很多地方别人这样写,我也没有太仔细研究过这样做的原因。只考察我每次用到MSG_TRACE的地方,确实do while看起来没什么用。所以我就把do while删掉了。它的第二个版本是这个样子的。
#define MSG_TRACE(msg,transport,isReceived) \
if (isMessageTraceOn()) { \
msgTrace((msg),(transport),(isReceived)); \
}
今天读了这篇文章,才知道采用do while的道理。
假设我要写如下的代码调用MSG_TRACE。
if (boolValue)
MSG_TRACE(msg,transport,isReceived);
else
doOtherThings();
那对于第二个版本的宏定义,展开后的代码如下。注意那个分号,它使得这个if else是不合法的。
if (boolValue)
if (isMessageTraceOn()) {
msgTrace((msg),(transport),(isReceived));
} ; //attention the semicolon
else
doOtherThings();
你说我调用MSG_TRACE的时候后面不加分号,如下。
if (boolValue)
MSG_TRACE(msg,transport,isReceived)
else
doOtherThings();
先不说这样不符合惯例。即使这样语法合法了,逻辑上也是有错误的。看他的展开形式,这个时候的else和内层的if匹配了,而不是本意的和外层if匹配。
if (boolValue)
if (isMessageTraceOn()) {
msgTrace((msg),(transport),(isReceived));
}
else
doOtherThings();
不用do while,用下面的第三个版本的方法把语句用花括号括起来,也同样会存在前述的问题。
#define MSG_TRACE(msg,transport,isReceived) \
{ \
if (isMessageTraceOn()) { \
msgTrace((msg),(transport),(isReceived)); \
} \
}
归纳一下,定义函数类型的宏的时候,用do while形式;写if和else语句的时候,用花括号。