在GCC中编译时使用`-Wextra`标志的缺点

时间:2015-02-07 11:45:17

标签: c gcc code-analysis compiler-warnings compiler-flags

我知道应该始终使用-Wall-Wextra进行编译,因为它们会启用警告并帮助我们理解错误,如果有的话。

我已经读过不建议使用-Wextra编译器标志,因为它太冗长而且有很多误报。

我读这篇文章时感到非常惊讶。所以我开始谷歌搜索它,但我没有得到任何答案,因为所有搜索结果显示的是" -Wextra标志做了什么?"。

所以,我的问题是

  • -Wextra标志在哪种情况下都会发出不必要的警告?
  • 是否可以阻止-Wextra标志启用导致GCC发出这些类型警告的其他标志?

6 个答案:

答案 0 :(得分:7)

关于-Wextra警告有用性的观点是相应的警告具有这些属性(或多或少):

  1. 他们会产生误报。

  2. 误报率相对较高。

  3. 调整代码以避免误报是一件麻烦事。

  4. 结果是,许多打开-Wall -Wextra的项目放弃了试图避免所有警告。因此,当您编译这样的项目时,您会看到成百上千的警告,几乎所有关于合法代码的警告。你应该看到的一个警告,在无尽的警告流中没有注意到。更糟糕的是:正常编译会发出如此多的警告这一事实使您对避免新代码引入的新警告感到邋。。一旦项目达到几十个警告,战斗通常结束;需要英勇的努力才能将警告计数恢复为零。

    以下是-Wextra

    咆哮的一些完全合法的代码示例
    void myClass_destruct(MyClass* me) {}
    

    它是一个析构函数,它是空的。然而,它应该只是为了方便在适当的点(子类析构函数)调用它,因此很容易向MyClass添加需要清理的东西。但是,-Wextra会对未使用的me参数进行吠叫。这迫使程序员编写如下代码:

    void myClass_destruct(MyClass* me) {
        (void)me;    //shut up the compiler barking about the unused parameter
    }
    

    这是明显的噪音。写这样的代码会很烦人。但是,为了在-Wextra制度下实现零警告计数,需要将此噪声添加到代码中。所以,你可以选择这三个中的任何两个:

    1. 清洁代码

    2. 零警告计数

    3. -Wextra警告

    4. 明智地选择你要放弃哪一个,你不会得到这三个。

答案 1 :(得分:4)

一些-Wextra警告正在强制执行适当的编码风格,这可能与某些人员流程冲突。这是避免它的唯一原因。我在这种情况下的解决方案是纠正'使用-Wno-*语法精确设置。

例如-Wextra暗示-Wempty-body会警告您某些控件结构的空体,例如ifelsewhile。但是如果你从一边追随“迭代”的话。实施风格和另一个需要大量警告,这对你来说会很不舒服。

以下是不断发展的代码示例:

void doSomething()
{
    if (validatePreConditions())
    {
         //TODO Handle it some time.
    }

    // ... Here you have real code.

}

如果您有-Werror,并且想要在没有执行前置条件检查的情况下开始测试,那么您就遇到了麻烦。

但这里存在陷阱,“开发中”可接受的是什么?代码将由生产时代码修复。所以我对这种情况的选择是有不同的警告和不同的构建配置文件。因此,例如,'开发人员'构建可以有空体,但是要合并到主线MUST NOT的任何东西都有这样的空白。

另一个例子是-Wignored-qualifiers,它包含在-Wextra中。在某些情况下,您知道编译器会忽略您的const限定符,但您只是为了自己的安慰而添加它(我个人不会在返回类型上支持这些限定符,但有些人认为它们做得很好有这样的标记)。

答案 2 :(得分:3)

  

其中所有情况都是-Wextra标志发出不必要的   警告?

您对不必要的定义是什么?您可以参考手册(这是4.9.2)来确切了解警告标志的作用。然后,您可以自己决定它是否适合您的代码库。

  

是否可以阻止-Wextra标志启用其他标志   导致GCC发出这些类型的警告?

-Wno-粘贴在警告前面以禁用它。并非所有警告都有警告标志,这意味着您可能必须坚持使用它。您通常也可以通过搜索某些警告标志并查看是否存在任何讨论来浏览bugtracker来查找更多信息。如果它不在文档中,它可能就在那里。开发人员也可能会表达为什么事情就是这样的理由。


为了解决您在评论中链接到的评论,

  

...或有关缺少字段初始值设定项的警告(当您还是时)   故意用{0}初始化一个结构,制作编译器   零自动初始化其他所有内容。)

这个论点没有实际意义,因为它已经是fixed。例如,以下代码生成no missing initializer fields warning

typedef struct { int a; int b; } S;

int main()
{
    S s = { 0 };
}

答案 3 :(得分:2)

这非常简单;

无用的警告是指永远不会指出实际错误的警告。

当然这是不可判定的,如果特定的警告能够“拯救培根”,就不可能事先知道。

所有海湾合作委员会的警告都会在某个时间或其他地方指出真正的错误,因此GCC消息的一般主题是 - 墙警告可能指向错误,如果他们不这样做很容易被压制。所以这与-Werror相得益彰。

-Wextra消息,OTOH指向真实错误的次数较少,或者可能指出在某些旧代码中常见的构造或者很难改变为表达代码的替代方式。所以有时他们可能确实过于冗长"。

对于新代码,您通常需要-Wextra。

对于旧代码,如果它不是"太冗长"它应该打开。

答案 4 :(得分:2)

基本上有三种类型的警告,GCC对于将它们分组或明确表示不是很好:

  1. 警告表示在源级别上甚至无法编译的正式无效,但由于某种原因(通常与旧代码的兼容性)允许这样做。这些是语言标准规定的。

  2. 警告表示如果程序到达发生警告的代码中的某个点,则程序必然会调用未定义的行为。如果代码无法访问,您的程序仍然有效,事实上,这可能会发生在以下情况:

    int i = 1;
    if (INT_MAX > 0x7fffffff) <<= 31;
    
  3. 纯粹是启发式的警告,并且本身并不表示程序的任何编程错误或无效,编译器只是警告您,您可能打算使用与您所写内容不同的内容。

  4. -Wextra开启了很多“3型”警告。

    一般来说,每个人都同意1型和2型是有价值的,但如上所述,即使是2型也可能有误报。类型3通常有很多误报;其中一些可以通过无害的代码更改来抑制,而其他人则需要实际上使您的代码更糟(或在本地关闭警告)以避免它们。

    这是人们不同意的地方。对于某些程序员,您只需打开-Wall -Wextra并在本地处理或禁用误报出现的警告。但是,除非你这样做,误报会产生很多噪音并可能降低信噪比,导致你在编译时习惯看到警告时不会注意到更严重的警告。

答案 5 :(得分:1)

有(至少)两个C程序员阵营:那些认为编译器有时可能知道更好的人,以及那些认为谁是编译器告诉我如何编写代码的人,毕竟,我知道我&# 39; d do。

Camp 1尽可能地发出警告,使用lint和其他代码检查器甚至可以获得有关可疑或可能损坏的代码的更多提示。

Camp 2并不喜欢机器一直指出他们的邋iness,更不用说花费额外的精力来修复他们认为完美的原样。

Camp 1受到业界的追捧,因为它们产生的错误代码更少,缺陷更少,客户错误报告更少。如果您正在为运载火箭,卫星设备,任何需要安全的设备编程,控制真正昂贵的设备,那么这个营地的思维模式就是您需要的。

第2营地显然太过频繁,您使用的许多应用程序(在您的计算机,智能手机,设备......上)的一般软件质量都表明了这一点。

你想属于什么阵营? -Wextra的缺点取决于这个答案。一个人的劣势是另一个人的优势。