如何优雅地克服无意义的 C++ 编译器警告?

Posted

技术标签:

【中文标题】如何优雅地克服无意义的 C++ 编译器警告?【英文标题】:How to overcome pointless C++ compiler warnings elegantly? 【发布时间】:2011-11-15 08:47:31 【问题描述】:

这个问题不绑定任何特定的编译器警告,以下只是一个例子。

目前,当我想要一个检查内部退出条件的循环时:

 while( true ) 
    doSomething();
    if( condition() ) 
       break;
    
    doSomethingElse();

我不能只用 Visual C++ 编写它——它会发出 C4127 conditional expression is constant 警告。尽管很明显while(true) 不可能是偶然编写的,但编译器会在我面前挥动它。

假设我想要编译时没有警告的代码。有解决方法可供我使用。

解决方法一是使用for(;;),但感觉很愚蠢——为什么我想要那个奇怪的东西而不是简洁优雅的惯用while(true)解决方法二 是在while( true ) 行之前使用#pragma warning( suppress),但它会添加一个比while 语句本身大两倍的巨大横幅。 解决方法三是为整个项目禁用 C4127(我在一个真实项目中看到过它),但随后所有可能有用的 C4127 实例也被禁用。

有什么优雅的方法可以消除无意义的警告吗?

【问题讨论】:

for(;;) forever.. g++ 在没有警告的情况下以最大可能的错误级别编译它。这个窗户是唯一的问题吗? 我同意@PrinceJohnWesley:for(;;) 是惯用的。 volatile int VeryTrue = 1; ... while(VeryTrue) ... ; 但我只是坚持使用 for(;;)。无论如何,每个用 C(++) 编写的人都必须知道这个习语。 @ern0 仅仅为了避免编译器警告,这是一个惊人且可能不可行的麻烦,因为您对编写不生成警告的 100% 等效代码有一些毫无意义的抑制。跨度> 【参考方案1】:

我会写for(;;),因为这是惯用的。

较新版本的 Visual C++ 并不像早期版本那样愚蠢。警告。 Visual C++ 10.0 编译使用 <windows.h> 的代码,警告级别为 4,无警告。

但是,如果您想关闭 Visual C++ 愚蠢的警告,请查看我的旧 anti-sillywarnings header,它是根据 [comp.lang.c++] 社区的输入创建的。

【讨论】:

windows.h 编译时没有警告,因为它里面塞满了#pragma warning(disable) 我喜欢反傻的警告标题,虽然其中一些看起来并不那个傻... @jbat100:最让我吃惊的是,警告 4510-4513 看起来与我之前没有意识到的警告 4623-4626 非常相似。【参考方案2】:

即使没有那个警告,我也会选择for(;;)。这不傻:它是一个没有条件的循环,这正是你想要表达的。

在我看来,这比使用 while 循环并在每次循环中测试 true 仍然为 true 更合乎逻辑(当然编译器会优化掉这个测试,因此它实际上不会影响性能)。

【讨论】:

-1 因为它只解决了 OP 给出的 example 而不是关于处理所有 无意义 警告的策略的实际问题 @Will 实际上这个问题是关于 *one 编译器中的 one 警告(C4127)。点赞。 @EJP "这个问题与任何特定的编译器警告无关,以下只是一个例子。" ... “有什么优雅的方法可以消除毫无意义的警告吗?” @我可以阅读吗,谢谢,包括你没有引用的部分。【参考方案3】:

什么可以——实际可实现——更多优雅的一行:

 #pragma warning ( suppress : 4127 )

我不能使用这个,因为我还在 VS2005 上,这个 doesn't work for all warnings。)

当然,对于您的情况,for(;;) 可能是务实的方法,但总的来说

如何优雅地克服无意义的 C++ 编译器警告?

我会说disable themproject wide。 (毕竟那里毫无意义)。并且,变化

如何优雅地克服false-positve C++ 编译器警告?

我想说,单个预处理器行看起来已经很不错了。

【讨论】:

什么是单行预处理器结构 @sharptooth - 我指的是你只需要一行来表达你禁用警告的意图。在 VS2005 上,你必须摆弄几行 push/disable/pop【参考方案4】:

我的理念是,如果您让编译器抑制警告,请在其中添加注释并说明原因。即使你认为这很愚蠢。 Pragma 脱颖而出并且可见。这是您代码中的一个很好的注释。

当您根据自己的想法而开始跳过 cmets 来抑制警告时,您可能会遇到潜在的麻烦。一年后编写代码的其他人可能会更改它,遇到麻烦并浪费宝贵的时间来寻找它。

顺便说一句,您正在寻找一种在没有任何一种情况下抑制警告的方法

使用编译指示 使用丑陋的代码 使用项目范围的抑制

那将是一种非常隐蔽的压制方法。

如果您不喜欢 pragma 的外观,请使用

bool alwaysTrue = true; // to prevent compiler warning C4127
while (alwaysTrue) 
    ...

【讨论】:

【参考方案5】:

我使用 while(true, 1) 来抑制这个警告。

【讨论】:

【参考方案6】:

做一些有趣的令牌粘贴:如果你可以交换

while(true)

While(true)

然后只需执行以下操作:

#define while_true for( ;; )
#define While(a) while_##a

【讨论】:

我不明白为什么。 for(;;) 的行为是纯粹的约定。它应该等同于不编译的while()。所以我把丑陋的for(;;)藏了起来,把while改了一点,跟原来的代码比较接近。 嗯,for(;;) 是一种广泛使用的过度设计结构,而您建议的是新引入的过度设计结构。 与这个答案相比,安装 Linux 和使用 GCC 的建议看起来更好。 投我一票死,没有人提供一个有效的例子来解决你的问题。 for 是正确的,但对某些人来说是丑陋的——我只是把它藏起来了。禁用警告可能会让你错过错误(更常见的错别字我做了一些统计数据(在 OSS 上),大约 2/3 的编码人员使用 for(;;) 而其他 1/3 用于 while(true)。for 有一个独特的 C-ish 风味,有些人可能会觉得恶心(它让我想起了数字食谱……) 我真的笑死了!谢谢@reder!让我们为这些代码增添趣味!【参考方案7】:

在许多情况下,令人满意的代码会按预期运行,但会产生大量警告。这就是为什么它们是警告而不是错误。他们惹恼你的事实是好的:警告旨在改变你的行为。你应该改过自新,而不是把它们扫到地毯下。

问题中的示例循环可以这样写:

for (; testExitCondition();) 
  doSomething();

在更复杂的情况下,循环计数器可以用作状态机的状态(每个动作都需要更新状态):

for (int state = stateBegin; state == stateTerminate;) 

  switch (state) 
  
    case stateBegin:
      //elaborate setup
      break;
    case state_1: 
      doSomething_1();
      break;
    case state_2: 
      doSomething_2();
      break;
    case state_n: 
      doSomething_n();
      break;


我最喜欢避免无意义的 C++ 警告的方法是使用 C# :)

诚然,这会产生大量毫无意义的 C# 警告,但没有什么是完美的。

天哪,看看反对票。证明 C++ 会损害你的幽默感。

【讨论】:

在这种情况下,答案已经在列表的底部。进一步的否决仅用于证明无幽默感的小事。我把这个问题当作一个玩笑,因为不言而喻,避免警告的方法是以不触发警告的方式编写代码。在 C# 中,可以全局或直接抑制特定成员的属性警告。人们很少使用它,因为彻底隐藏警告是个坏主意。

以上是关于如何优雅地克服无意义的 C++ 编译器警告?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 c++ 编译器不会警告返回对局部变量的引用?

记录一次奇怪但是很有意义的程序编译警告

忘记在 do...while 循环中做

如何抑制有关 C++ 中未使用变量的警告?

如何在我自己的代码中使用 Visual C++ 在不运行静态代码分析的情况下导致 SAL 编译器警告

C ++如何禁用具有不同符号变量比较的特定行的编译器警告?