在C宏中,是否应该优先使用do { ... } while(0,0)而不是do { ... } while(0)?

17
最近有一位客户对我们公司的C代码库进行了静态分析,并给了我们结果。其中有一个有用的补丁是要求将著名的 do { ... } while(0) 宏更改为 do { ... } while(0,0)。我理解他们的补丁是什么意思(使用序列运算符使其评估为第二个“0”的值,因此效果相同),但不清楚为什么他们会喜欢第二种形式而不是第一种形式。
是否有合法的理由支持使用第二种宏的形式,或者我们的客户的静态分析过于追求细节了?

5
您的客户的静态分析工具肯定是过度某些方面了。 - Chris Lutz
7
我会选择“过于冗余”。 - Greg Hewgill
20
是的,(0,0) 看起来像猫头鹰。也许他们认为你的代码需要更多的猫头鹰。 - Steve Jessop
3
我明白了。这段代码必须处理鼠标悬停事件,而猫头鹰则在那里捕捉老鼠。 - bmargulies
6
在 C 和 C++ 中,0,0 不是一个常量表达式,但 0 是。因此,编译器更有可能会对后者发出警告而不是前者。但也更有可能优化掉后者而不是前者,所以我不太明白他们改变后者会有什么收益。 - Johannes Schaub - litb
显示剩余4条评论
3个回答

14

只是猜测为什么他们建议使用

do { ... } while(0,0)

结束

do { ... } while(0)
尽管两种方法没有行为差异,且在运行时代价也应该相同。但我猜测静态分析工具在简单情况下由常量控制 while 循环时会报错,而使用 0,0 时则不会。顾客建议的可能只是为了避免从工具中得到大量错误警告。
例如,有时我会遇到想要有一个由常量控制的条件语句的情况,但编译器会发出一个关于条件表达式评估为一个常量的警告。然后我就必须采取一些措施来解决编译器的警告问题(因为我不喜欢有虚假的警告)。您的客户建议是我用过的其中一种方法,可以消除那个警告,但在我的情况下它并不是在控制一个while循环,而是用于处理"始终失败"的断言。有时,我会有一段永远不会执行的代码(比如一个 switch 的默认情况),在这种情况下,我可能会有一个总是失败的带有某些消息的断言:
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))

告诉工具供应商修复问题可能是好事,但也可能存在合理情况,他们确实想要诊断由常量布尔表达式控制的循环。更不用说,即使你成功说服工具供应商做出改变,那也不能帮助你在接下来的一年左右时间内得到真正的解决方案。


2
+1 这可能就是答案,但如果是这样的话,这些警告应该使用命令行选项禁用。为什么要费尽周折,当你可以关闭不必要的步骤? - Chris Lutz
1
首先,调整编译器或工具选项可能被视为一种繁琐的操作。与制作文件或控制构建的任何其他内容相比,这通常更像黑魔法而不是C预处理程序技巧(这可不是闲话)。其次,您可能不希望禁用所有警告 - 可能只是针对似乎需要这些愚蠢技巧的调试宏。 - Michael Burr
1
现在我的静态分析报错了,“冗余的逗号左参数”。有时你就是赢不了。 - John

13

使用while(0,0)可以防止Microsoft编译器生成有关常量条件(警告C4127)的警告。

当启用此警告(例如使用/W4或/Wall时),可以通过这个小技巧(另一个线程中看到)逐个关闭。

编辑:自Visual Studio 2017 15.3以来,while(0)不再发出警告(参见Constant Conditionals)。你可以摆脱(0,0)啦!


3
因为某些原因,我对此并不感到惊讶。 - user1143634

11

好的,我来回答一下:

有什么正当理由可以选择宏的第二种形式吗?

没有正当理由。两种形式都会始终计算为 false,并且任何一个良好的编译器可能会将第二种形式转换为汇编代码中的第一种形式。如果在某些情况下使用第二种形式是无效的,C语言已经存在了足够长的时间,使得比我更厉害的大牛们已经发现了这个问题。

如果你喜欢让你的代码对你眨眼,那就使用 while(0,0)。否则,使用其他 C 程序员使用的方法,并告诉你的客户的静态分析工具去管它。


1
我指的是对00,0的评估,而不是一般的do { } while(0)循环。 - Chris Lutz
1
“有什么好处?”:在while循环条件中使用0,0所传达的好处。静态分析似乎认为有好处,但是这个答案虽然被接受,却没有揭示出来,所以我们不得不猜测。 - Clifford
1
@Chris:我明白你的意思,但我很好奇,希望有人能告诉我们为什么该工具会建议这样做 - 即使思路是错误的。 我找不到任何关于这种习语的参考。即使是MISRA C准则也没有建议这样做。 如果OP能告诉我们该工具是什么会更好。 - Clifford
3
将0,0作为参数可以消除VC++警告4127。这就是这种模式存在的合理原因。如果您认为0,0是一种不可接受的黑客方式,那么为什么您认为使用do{}while(0)本身不是更糟糕的黑客方式? - ThreeBit
@Clifford 我的意思是针对警告(而非代码生成),实际上现实世界中的编译器通常不会将阶段真正分开,它们会保留“起源”历史记录,并且可以知道何时消除警告,因为它们识别了来自宏扩展的常见语法结构,比如常量控制流结构。 - Alex Celeste
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接