繁体   English   中英

是'警告C4127`(条件表达式是不变的)有用吗?

[英]is `warning C4127` (conditional expression is constant) ever helpful?

回答这篇文章时,我建议对多行宏使用do {...} while(0)

在MSVC上,我发现此代码抛出:

warning C4127: conditional expression is constant

为了使代码无警告,我需要选择以下丑陋的替代方案之一:

选项1

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4127)
#endif
code_using_macro_that_generates_C4217;
#ifdef _MSC_VER
#pragma warning(pop)
#endif

选项2
将我的宏定义为:

#define MULTI_LINE_MACRO do { ... } while(0,0)

要么

#define MULTI_LINE_MACRO do { ... } while((void)0,0)

一些程序员也称为“猫头鹰”,因为(0,0)看起来像猫头鹰。

选项3
定义一个新的宏WHILE_0,它不会生成警告并使用它而不是while(0)

问题
我相信所有选择都或多或少都是可怕的。 为什么MSVC会为看似正确的代码生成此警告,并激励我在代码中添加一些丑陋以保持代码警告免费?

我相信条件中的常量表达式是完全有效的,特别是在基于编译器优化代码的能力的构造中。

此外,我没有得到warning C4127的代码warning C4127

void foo(unsigned bar)
{
    while (bar >= 0)
        ;
} 

我的问题是:不是warning C4127: conditional expression is constant完全没用,它不会激发丑陋的代码吗? 这个警告是否有助于编写更好的代码?

我不认为它有用。 相反,有更多的误报而不仅仅是do .. while(0)成语。 想想像这样的结构

if(sizeof(long) == 8) { /* ... */ }
if(SOME_CONSTANT_MACRO) { /* ... */ }

前者不能被#if指令替换,后者可以,但是一些编码风格指南更喜欢if版本,因为仍然对死代码进行语法检查(在其他平台或其他编译时配置中没有死)有些人发现阅读起来更好。

警告(除了标准所要求的警告之外,其中大多数应被视为错误)通常是针对有效的代码发出的,但可能会执行除预期之外的其他操作。 if(0)或类似的东西看起来很傻,但看起来不像“语法检查这个否则死代码”的意图。 它可能会困扰读者,但它是明确的,我不知道这是如何偶然发生的。

从目前给出的示例(我没有自己的MSVC进行测试),似乎警告是针对C语言意义上的常量表达式(也就是说,不是可以是常量折叠但是语法上的东西不是一个常量表达式),所以它不是为if(array)或者if(function)发出的(例如gcc -Wall会发出警告,因为它可能是一个函数调用)。

while(0,0)更糟糕,在我看来,它会触发一个警告,用gcc -Wall表示逗号操作符的左侧没有副作用,我可以想象这个警告偶尔会有用(通常是容易避免)。 while((void)0,0)此警告消失。

我建议关闭警告。

该条件表达式是恒定一定的警告可以是有用的。 在许多情况下,它可能指向代码中的逻辑错误。

例如,如果您写的内容如下:

if (x != NULL) { /* ... */ }

其中x是数组对象,表达式有效,但表达式x衰减到指向数组初始元素的指针,该元素不能是空指针。 我不知道是否会产生相同的错误,但它是同类错误的一个例子。

当然,它并不总是有用的。 在你的情况下,

do { /* ... */ } while (0)

idiom是编写宏定义的最佳方式,该宏定义旨在用于需要语句的上下文中。 在另一个上下文中使用while (0)可能是一个逻辑错误[*]。

不幸的是,你的编译器并不认为它是一个常见的习惯用法。 产生良好的警告是棘手的; 编译器必须超越语言规则并推断程序员的意图。

在这种情况下,使用一些特定于编译器的方法来抑制警告(只要它不破坏其他编译器的代码)可能是最好的方法。 在所有情况下使用命令行选项来抑制警告将是过度的; 你可能会错过代码中其他地方的有效警告。

显然写入while (0,0)而不是while (0)可以避免警告。 如果您这样做,您应该添加一个注释,清楚地表明它是您的特定编译器的解决方法。 编译器不应该警告while (0,0)或任何其他等效代码没有特殊原因。

[*]如果你想能够使用break来跳出它,那么写一个do { /* ... */ } while (0)语句是有意义的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM