一位客户最近对我雇主的 C 代码库进行了静态分析并向我们提供了结果。有用的补丁之一是将著名的
do { ... } while(0)
宏更改为 do { ... } while(0,0)
的请求。我理解他们的补丁正在做什么(使用序列运算符是否有合理的理由说明为什么人们应该更喜欢宏的第二种形式,或者我们客户的静态分析是否过于迂腐?
只是猜测他们为什么会建议使用
do { ... } while(0,0)
结束
do { ... } while(0)
尽管两者之间没有行为差异并且应该没有运行时成本差异。
我的猜测是,静态分析工具会抱怨
while
循环在更简单的情况下由常量控制,而在使用 0,0
时则不会。客户的建议可能只是为了让他们不会从该工具中得到一堆误报。
例如,我偶尔会遇到这样的情况:我想要一个由常量控制的条件语句,但编译器会抱怨条件表达式计算为常量的警告。然后我必须跳过一些麻烦才能让编译器停止抱怨(因为我不喜欢出现虚假警告)。
您的客户的建议是我用来消除该警告的因素之一,尽管在我的情况下,它不是控制
while
循环,而是处理“总是失败”的断言。有时,我会有一个永远不应该执行的代码区域(可能是开关的默认情况)。在这种情况下,我的断言可能总是失败并显示一些消息:
assert( !"We should have never gotten here, dammit...");
但是,我使用的至少一个编译器会发出关于表达式始终评估为 false 的警告。但是,如果我将其更改为:
assert( ("We should have never gotten here, dammit...", 0));
警告消失了,每个人都很高兴。我猜即使您客户的静态分析工具也会如此。请注意,我通常将跳圈隐藏在宏后面,例如:
#define ASSERT_FAIL( x) assert( ((x), 0))
能够告诉工具供应商解决问题可能会很好,但可能存在合法情况,他们实际上确实想要诊断由常量布尔表达式控制的循环。更不用说即使您说服工具供应商做出这样的更改,这对您在明年左右的时间也没有帮助,因此可能需要实际修复。
好吧,我去寻求答案:
是否有合理的理由为什么人们应该更喜欢宏的第二种形式......?
不。没有正当理由。两者的计算结果总是为 false,并且任何像样的编译器都可能将第二个编译器转换为程序集中的第一个编译器。如果有任何原因导致它在某些情况下无效,那么 C 已经存在了足够长的时间,以至于比 I 更伟大的大师都发现了这个原因。
如果你喜欢你的代码让你的代码像猫头鹰一样看着你,请使用
while(0,0)
。否则,请使用 C 编程世界的其他部分所使用的内容,并告诉客户的静态分析工具将其推送。