在C宏中,应该更喜欢做{…}而(0,0)而不是{…}而(0)?

一位客户最近对我雇主的C代码库进行了静态分析,并向我们提供了结果。 在有用的补丁中,要求将着名的do { ... } while(0)宏更改为do { ... } while(0,0) 。 我理解他们的补丁正在做什么(使用序列运算符将evaluate 返回到第二个“0”的值,因此效果是相同的)但是不清楚他们为什么喜欢第二个表单而不是第一个表单。

有没有合理的理由为什么人们应该更喜欢第二种forms的宏观,还是我们客户的静态分析过于迂腐?

好吧,我会回答一下:

有没有合理的理由为什么人们应该更喜欢宏观的第二种forms……?

不,没有合理的理由。 两者总是评估为false,任何体面的编译器都可能将第二个转换为程序集中的第一个。 如果在某些情况下有任何理由使其无效,那么C已经存在很长时间了,因为这个理由可以被比我更大的大师发现。

如果你喜欢你的代码让猫头鹰盯着你,请使用while(0,0) 。 否则,使用C编程世界的其他部分使用并告诉客户的静态分析工具来推送它。

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

 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)) 

能够告诉工具供应商解决问题可能会很好,但可能存在合法的情况,他们确实想要诊断由常量布尔表达式控制的循环。 更不用说即使你说服一个工具供应商进行这样的改变,这对你在明年左右的实际上可能需要修复的东西没有帮助。

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

当启用此警告时(例如使用/ W4或/ Wall),可以根据具体情况逐个关闭它( 请参阅此其他线程 )。

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