作为C和Objective-C程序员,我对编译器警告标志有些偏执。
我通常会尝试为我使用的编译器找到完整的警告标志列表,然后打开大多数警告标志,除非我确实有一个很好的理由不启用它。

我个人认为,这实际上可能会提高编码技能以及潜在的代码可移植性,从而防止出现某些问题,因为这会迫使您注意所有问题。很少的细节,潜在的实现和体系结构问题等等...

即使您是一个有经验的程序员,我也认为它是一种很好的日常学习工具。

对于这个问题的主观部分,我有兴趣听取其他有关此主题的开发人员(主要是C,Objective-C和C ++)的信息。
您实际上是否关心脚步警告等内容?如果是或否,为什么?

现在关于Objective-C,我最近完全切换到了LLVM工具链(使用Clang),而不是GCC。

在我的产品上代码,我通常会设置此警告标志(明确地,即使其中一些可能被-Wall覆盖):


-Wall
-Wbad-function-cast
-Wcast-align
-Wconversion
-W声明后声明
-W弃用的实现
-Wextra
-Wfloat-equal
-Wformat = 2
-Wformat-nonliteral
-Wfour-char-constants
-Wimplicit-atomic-properties
-Wmissing-braces
-Wmissing-declarations
-Wmissing字段初始化器
-Wmissing格式属性
-Wmissing-noreturn
-Wmissing原型
-Wnested-externs
-Wnewline-eof
-Wold-style定义
-长度字符串
-括号
-Wpointer-arith
-Wredundant-decls
-Wreturn类型
-Wsequence-point
-Wshadow
-Wshorten-64-to-32
-Wsign-compare
-Wsign-conversion
-Wstrict原型
-Wstrict选择器匹配
-Wswitch
-Wswitch默认值
-Wswitch枚举
-Wundeclared选择器
-未初始化
-Wunknown-pragmas
-Wunreachable代码
-Wunused函数
-Wunused标签
-Wunused参数
-Wunused值
-Wunused -variable
-Wwrite-strings

我有兴趣听听其他开发人员对此有何评论。例如,您认为我错过了Clang(Objective-C)的特定标志,为什么?
或者您认为特定标志没有用(或根本不需要),为什么?

EDIT

要澄清这个问题,请注意-Wall仅提供了一些基本警告。
实际上,它们是更多警告标志,没有被-Wall覆盖,因此是问题和我提供的列表。 />

评论

我很想说这可能应该保留在Stack Overflow上,因为这是关于工具使用的问题,但是我们将看到社区的变化。

感谢您的评论:)在某种程度上,我同意您的意见,这就是为什么我最初将其发布在StackOverflow上的原因(也是因为我不是这里的普通用户,所以让我感到羞耻)。得到了很多意见,赞誉等等。。。但是却没有一个答案。。。正如人们建议移动它。。。让我们来看一下:)

好吧,希望我们能给您一个很好的答案。祝好运。 :)

对于C和gcc,-Wwrite-strings使它成为与语言非常相似但与C完全不同的语言的编译器。仅出于这个原因,我不使用该选项。除了您指定的以外,我使用-pedantic -Wstrict-overflow = 5 -Winline -Wundef -Wcast-qual -Wologic-op -Wstrict-aliasing = 2和-Wno-missing-braces -Wno-missing-field-initializers对于完全合理的初始化程序结构,无论obj = {0};。我也发现-Wconversion比有用的警告提供了更多的“垃圾邮件” :)

不值得回答,但是...我始终启用-Wall(请注意,我在说C)。我发现未使用的参数可能很烦人(有时您仅需为回调原型或诸如信号处理程序之类的东西提供它)。我也发现Clang警告,告诉您以前没有声明过函数/变量,除非您将它们放在头文件中或声明为静态(即使您在此处/使用它们之前声明/定义它们)也很烦。我不喜欢其他几个,但更糟糕的是GCC的误导性缩进警告。好问题。

#1 楼

就上下文而言,我是在Google工作的Clang开发人员。在Google,我们已经(基本上)将Clang的诊断程序推广到了我们所有的C ++开发人员,并且我们也将Clang的警告也视为错误。作为Clang开发人员和Clang诊断程序的较大用户之一,我将尝试阐明这些标志以及如何使用它们。请注意,我描述的所有内容通常都适用于Clang,而不特定于C,C ++或Objective-C。

TL; DR版本:请至少在所有新版本中使用-Wall-Werror代码
您正在开发。我们(编译器开发人员)在此处添加警告,以求有道理:他们会发现错误。如果您发现警告提示您发现错误,请同时打开
。在这里尝试-Wextra寻找一堆不错的候选人。如果
其中之一对您来说太吵而无法盈利,请提交错误。如果您编写的代码
包含“明显的”错误,但是编译器未发出警告,请提交错误。

现在是长版。首先是警告标志分组的背景。
Clang中有很多警告“分组”(在GCC中是有限的)。与该讨论相关的一些警告:


默认情况下:除非您明确禁用它们,否则这些警告始终处于启用状态。

-Wall:这些是警告开发人员对他们的价值和虚假阳性率都充满信心。

-Wextra:这些警告被认为是有价值且合理的
(即,它们不是越野车),但它们可能有很高的假阳性率或
常见的哲学异议。

-Weverything:这是一个疯狂的组织,从字面上使每一个
发出警告铛。不要在您的代码中使用它。它仅用于
Clang开发人员或探究存在的警告。

上面提到的两个主要标准可指导警告进入的位置
叮当声,让我们澄清一下它们的真正含义。第一个是特定警告发生的潜在值。这是警告触发并正确识别代码后对用户(开发人员)的预期好处。
识别代码中的问题。

第二个条件是假阳性报告。这些是警告会在代码上触发的情况,但是由于程序的上下文或某些其他约束,实际上不会发生被引用的潜在问题。警告的代码实际上行为正确。当警告从未打算在该代码模式上触发警告时,这些警告尤其重要。相反,这是警告的实施缺陷,导致
将其触发。

对于Clang警告,该值必须是正确性,
风格,品味或编码约定的术语。这限制了可用的警告集,排除了经常请求的警告,例如,当在{}语句的主体周围不使用if时,发出警告
。叮当声
非常不容忍假阳性。与大多数其他编译器不同,它会使用各种令人难以置信的信息源来修剪误报,包括
构造的确切拼写,是否存在多余的(),强制转换,
或甚至是预处理器宏!

现在让我们来看看Clang的一些实际示例警告,并查看它们的分类方式。首先,一个默认的警告:

% nl x.cc
     1  class C { const int x; };

% clang -fsyntax-only x.cc
x.cc:1:7: warning: class 'C' does not declare any constructor to initialize its non-modifiable members
class C { const int x; };
      ^
x.cc:1:21: note: const member 'x' will never be initialized
class C { const int x; };
                    ^
1 warning generated.


这里不需要标志来获得此警告。这样做的理由是,
代码永远不会真正正确,从而给警告以高价值,并且
仅对Clang可以证明属于该存储桶的代码发出警告,将
设置为零。误报率。

% nl x2.cc
     1  int f(int x_) {
     2    int x = x;
     3    return x;
     4  }

% clang -fsyntax-only -Wall x2.cc
x2.cc:2:11: warning: variable 'x' is uninitialized when used within its own initialization [-Wuninitialized]
  int x = x;
      ~   ^
1 warning generated.


此警告要求使用-Wall标志。原因是有
我们警告过要使用(无论是好是坏)代码模式的大量代码,我们警告有意产生未初始化的
值。从哲学上讲,我认为这没有意义,但是许多其他人不同意,并且这种观点分歧的现实是在-Wall标志下发出警告的原因。它仍然具有很高的价值和非常低的
假阳性率,但是在某些代码库上,它不是启动器。

% nl x3.cc
     1  void g(int x);
     2  void f(int arr[], unsigned int size) {
     3    for (int i = 0; i < size; ++i)
     4      g(arr[i]);
     5  }

% clang -fsyntax-only -Wextra x3.cc
x3.cc:3:21: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
  for (int i = 0; i < size; ++i)
                  ~ ^ ~~~~
1 warning generated.


此警告要求-Wextra标志。原因是在非常大的代码库中,比较符号不匹配的情况非常普遍。
虽然此警告的确发现了一些错误,但当代码出现错误时,该代码很可能是错误的。
用户写道,平均而言,它是相当低的。结果是极高的假阳性率。但是,如果由于奇怪的升级规则而导致程序中存在错误,则当警告该错误标志为相对较高的值时,常常会非常微妙地发出此警告。因此,Clang
提供了该警告并将其暴露在一个标志下。

通常,警告不会在-Wextra标志之外存在很长时间。 Clang尝试
非常努力地执行不会看到无法正常使用和测试的警告。
-Weverything启用的其他警告通常是在
活跃的开发中或带有活动的bug的警告。要么将它们固定并放置在适当的标志下,要么应该将其删除。

现在我们已经了解了这些东西如何与Clang一起使用,让我们
尝试回到最初的问题:您应该为自己的开发打开哪些警告?不幸的是,答案取决于它。请考虑以下问题,以帮助确定哪种警告最适合您的情况。


您是否控制了所有代码,或者其中一些代码可以控制?外部的吗?
你的目标是什么?捕获错误或编写更好的代码?
您的错误肯定容忍度是多少?您愿意编写额外的代码
来定期使警告静音吗?

首先,如果您不控制代码,请不要尝试过度使用代码
那里的警告。准备关闭一些。
世界上有很多错误的代码,您可能无法修复所有问题。那没问题。努力找到一种方法来将精力集中在控制的代码上。

接下来,找出警告中想要的内容。对于
不同的人来说是不同的。 Clang会尝试警告严重错误,
或我们有悠久历史的代码模式,这些错误表明错误率非常高。通过启用-Wall,您将获得更多攻击性的警告,旨在捕获Clang代码在C ++开发人员中发现的最常见错误。但是有了这两种方法,
假阳性率应该仍然很低。

最后,如果您完全愿意在每一个
转弯使*假阳性*沉默,进行-Wextra。如果您注意到警告,请提交错误,这些警告正在捕获很多真正的错误,但这些警告具有愚蠢或毫无意义的误报。我们一直在努力寻找方法,将越来越多的错误发现逻辑引入到-Wextra中,从而可以避免误报。

许多会发现这些选项都不适合他们。在Google,我们已经关闭了-Wall中的一些警告,原因是现有的许多代码
都违反了该警告。即使
-Wall均未启用这些警告,我们也已明确将其打开,因为它们对我们来说具有特别高的价值。您的里程会有所不同,但是可能会以类似的方式发生变化。
启用一些主要警告而不是全部-Wall往往会更好。

我鼓励所有人为任何非遗留代码打开-Wextra。对于
新代码,此处的警告几乎总是有价值的,并且确实使
开发代码的经验更好。相反,我鼓励所有人
不要启用-Wall之后的标志。如果您发现-Wextra
不包括但对您完全有价值的警告,只需提交一个错误
,我们很可能将其放在-Wextra下。是否在-Wextra中明确启用
警告的子集在很大程度上取决于您的代码,您的
编码样式以及维护该列表是否比修复-Wextra所发现的所有内容容易。 />
仅在OP的警告列表(包括-Wextra-Wall)中
这两个组均不覆盖以下警告(或默认为
启用)。第一组强调为什么过分依赖显式警告标志会很糟糕:这些都不是在Clang中实现的!仅出于GCC兼容性而在命令行上接受它们。


-Wextra
-Wbad-function-cast
-Wdeclaration-after-statement
-Wmissing-format-attribute
-Wmissing-noreturn
-Wnested-externs
-Wnewline-eof
-Wold-style-definition
-Wredundant-decls
-Wsequence-point
-Wstrict-prototypes

原始列表中的下一个不必要的警告是与该列表中的其他元素冗余的





-Wswitch-default--Wformat-nonliteral的子集


-Wformat=2- -Wshorten-64-to-32的子集


-Wconversion--Wsign-conversion的子集


也有一些警告,它们在类别上更加不同。
它们处理的是语言方言变体,而不是越野车或非越野车的代码。除-Wconversion外,所有这些都是Clang提供的
语言扩展的警告。 Clang是否会警告使用它们
取决于扩展的流行程度。 Clang旨在实现GCC兼容性,因此在很多情况下,它通过广泛使用的隐式语言扩展来缓解这种情况。如OP所述,-Wwrite-strings是来自GCC的兼容性标志,它实际上改变了程序的语义。我对此标志深表歉意,但是由于它现在已有的遗产,我们必须予以支持。


-Wwrite-strings
-Wfour-char-constants
-Wpointer-arith

实际上使潜在有趣的警告的其余选项如下:


-Wwrite-strings
-Wcast-align
-Wconversion
-Wfloat-equal
-Wformat=2
-Wimplicit-atomic-properties
-Wmissing-declarations
-Wmissing-prototypes
-Woverlength-strings
-Wshadow
-Wstrict-selector-match
-Wundeclared-selector

原因这些不是在-Wunreachable-code-Wall中并不总是很清楚。对于其中的许多
,它们实际上是基于GCC警告(-Wextra
-Wconversion等),因此Clang试图模仿GCC的行为。我们正在
将其中一些缓慢分解为更细粒度和有用的警告。
然后这些警告更有可能使其成为顶级警告组之一。也就是说,要警告一句,-Wshadow的范围如此广泛,以至于在可预见的将来它可能仍将保持其自己的“顶级”类别。 GCC拥有的其他一些警告但其价值低且误报率高的警告可能会被归类为类似的无人区。

这些原因并非一成不变的其他原因较大的存储桶中包括简单的错误,非常严重的假阳性问题以及开发中的警告。
我将研究可以识别的错误。它们都应该最终迁移到适当的大存储桶标志中,或者从Clang中删除。

我希望这可以澄清Clang的警告情况并提供一些
试图选择警告或警告的人的见解。
公司的警告。

评论


出色的答案!非常感谢。我需要重新阅读几次,但是稍后我会发表一些评论。再次感谢!

– Macmade
2011-12-12在16:34



@钱德勒·卡鲁斯:好答案!但是,如果发生任何更改,您是否可以更新它?我在上一个列表中使用了所有警告,但也许有些警告已移至Wextra?

–gartenriese
15年1月19日在21:28

这是一个很棒的帖子。但是,我发现找到新的警告标志非常有用,因此,令我失望的是,尽管您承认它对这种探索很有用,但您似乎对“一切”团体都持消极态度。

–凯尔·斯特兰德(Kyle Strand)
15年9月15日在15:03

@钱德勒·卡鲁斯(Chandler Carruth):我同意警告“从不正确”的背后的理由。只是没有-Wno关闭warn_no_constructor_for_refconst使PITA使用Boost.ConceptCheck等:github.com/boostorg/concept_check/blob/…

–mloskot
19年5月4日在21:08



请至少对正在开发的任何新代码使用-Wall和-Werror。我们(编译器开发人员)在此处添加警告有充分的理由:他们发现错误。为此加油!不能夸大其词!这是我很久以来一直在“追求”的东西-价值数十年。作为IOCCC参与者(也是冠军)的FWIW,我可以从这个角度说,真正的警告是您最好的朋友。 IOCCC称赞不会触发警告的代码,他们甚至说尝试使用Clang -Wall -Wextra -Weverything`进行干净的编译-我完全同意。 (1/2)

–Pryftan
20 Jan 17 '15:26



#2 楼

我不使用Clang,但希望您也不要介意我的意见。我还使用最大警告级别(我假设这是-Wall的意思),并且将警告视为错误(我假设这是-Werror的意思),并且我只禁用了那些没有太大意义的警告。实际上,C#编译器未发出某些非常有用的警告使我非常恼火,并且必须运行特殊的代码分析工具才能看到它们。我喜欢警告,因为它们可以帮助我捕获代码中的小错误和错误。我非常喜欢它们,以至于当我为正确的一段代码发出警告时,无论如何我都会重构该代码段,这样就不会发出警告,而是禁用警告,或者--even更糟的是-让它出现并忽略它。我认为警告太棒了,我希望警告更多。

评论


感谢你的回答。不幸的是,-Wall仅提供基本警告。 -Wall无法覆盖很多现有的警告标志,因此这是我的问题。

– Macmade
2011-12-10 17:17

@Macmade True,但也有-Wextra。我个人认为,GCC警告可能比Clang更轻描淡写。但这完全是另一回事。

–Pryftan
20 Jan 17 '15:36

#3 楼

我通常会为新项目使用Xcode的默认设置。它在帮助与烦恼之间取得了良好的平衡。警告和其他编译器选项的任何特定列表都将主要基于个人喜好或项目要求,因此,我认为尝试遍历列表并主张或反对特定警告并没有太多价值。如果它适合您,那就太好了。如果发现您犯了一些错误,编译器应该可以检测到该错误,并且希望在以后获得帮助,请寻找一个编译器选项以发出警告并打开它。

许多程序员提倡的一件事是打开“将警告视为错误”(-Werror)选项,以防止在有任何警告的情况下成功完成构建。

评论


感谢你的回答!我同意-Werror。实际上,当我使用Clang时,我使用了编译指示(#pragma clang diagnostic)来设置所有这些警告,并且它们都设置为致命错误,因此与-Werror:相同。

– Macmade
2011-11-30 22:12

#4 楼

我认为人们关心警告的最好证据是它们存在并且被广泛使用。我强烈认为,编译期间捕获的错误越多越好。如果这不是一个普遍存在的信念,那么每个人都会使用弱动态类型的语言,因为它们的编译器或解释器为您提供了更多的回旋余地。相反,即使在脚本语言上,也很流行使用strict标志。在静态强类型语言上,人们不仅经常使用-Wall -Werror,而且他们常常发现警告如此有价值,以至于他们甚至想要更多。因此,他们购买了诸如Coverity之类的静态分析工具,其唯一目的是提供警告。

这并不意味着没有批评者。许多开发人员认为警告是短期内对他们不利,而不是长期内对他们不利,并且不要尝试解决根本问题。因此,您会看到我昨天遇到的类似以下代码段的可爱代码:

node = node; // Shut up compiler warning


评论


感谢您的回答。问题是我经常看到人们在没有-Werror的情况下工作,而实际上却忽略了编译器发出的警告。或者,如果这样做,通常只是坚持使用-Wall。我在问题中提供的大多数标志都没有被-Wall覆盖,我个人认为它们也是必不可少的。那我只是偏执吗? ; )

– Macmade
2011-12-10 17:21



奇怪...我认为它们没有被广泛使用-即使在现在。我怀疑它们不是因为人类很懒惰,而且似乎也不欣赏他们可能错过或没有想到的某些事情。对于某些人来说,是因为他们拒绝相信自己的不完美等。但是对于其他人来说,可能是他们不了解其中的含义。 @Macmade您不是-启用警告是个好主意。当然,对于某些项目来说,有些问题是个问题,有些琐碎的事情虽然不够完善,但警告是您的朋友,因此您绝对正确。

–Pryftan
20年1月17日在15:38

而卡尔在那里就关闭了编译警告很有趣。感谢那。当然,这很危险,但是它是关闭编译器的一种有趣而厚脸皮的方法。你还记得那是哪里吗?在哪个项目中?谢谢。

–Pryftan
20年1月17日在15:40

这很可能在工作中的专有项目中。

–卡尔·比勒费尔德(Karl Bielefeldt)
20年1月17日在16:42

#5 楼

通常,我更倾向于-Wall,并且绝对相信也包括-Werror。模块永远不要有预期的警告。您最终将收到另一个警告,并且错过它。这实际上是一个问题。

这还取决于您是在新项目还是旧项目中添加“ -Wall -Werror”。如果它是新的,那就去做,并要求完美,否则您可能需要几天或几周的编辑和测试时间。我只是在一个稍旧的小型项目中执行了此操作,然后花了两三天时间删除了警告。我认为代码现在比较干净。

换句话说,请尝试一下。

Randy

评论


如果您只关心-Wall和-Werror,我想您应该重新阅读该问题。 -Wall不能覆盖许多警告标志。无论如何,谢谢您的回答。

– Macmade
2011-12-10 17:16