就上下文而言,我是在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开发人员或探索存在的警告。
上面提到了两个主要标准,它们指导警告在Clang中的使用位置,并让我们阐明这些警告的真正含义。第一个是特定警告发生的潜在
值。当警告触发并正确
识别代码问题时,这是对用户(开发人员)的预期收益。
第二个标准是假阳性报告的想法。在这些情况下,警告会在代码上触发,但是由于程序的上下文或某些其他约束,实际上并未发生被引用的潜在问题。警告的代码实际上行为正确。当警告从未打算在该代码模式上触发时,这些问题尤其严重。而是,警告的实现中存在缺陷,导致警告在那里触发。
对于Clang警告,该值必须是正确性,而不是样式,口味或编码约定。这限制了可用的警告集,排除了经常请求的警告,例如{}
在if
语句主体周围不使用s时发出的警告。克朗对假阳性也很不宽容。与大多数其他编译器不同,它将使用各种信息源来修剪误报,包括构造的确切拼写,是否存在多余的'()',强制转换甚至预处理器宏!
现在,让我们来看一些来自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.
Clang需要-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
通常是处于活动开发中或带有活动错误的警告。要么将它们固定并放置在适当的标记下,要么将其删除。
既然我们已经了解了这些东西如何与Clang一起工作,让我们回到最初的问题:您应该为开发打开什么警告?不幸的是,答案取决于它。考虑以下问题,以帮助确定哪种警告最适合您的情况。
- 您可以控制所有代码,还是其中一些是外部代码?
- 你的目标是什么?捕获错误或编写更好的代码?
- 您的假阳性容忍度是多少?您是否愿意编写额外的代码来定期使警告静音?
首先,如果您不控制代码,请不要尝试在上面打开额外的警告。准备关闭一些。世界上有很多错误的代码,您可能无法修复所有错误代码。那没问题。努力找到一个方式来集中你的代码的努力,你的控制。
接下来,找出警告中想要的内容。对于不同的人来说这是不同的。Clang会尝试警告严重的错误,或我们有悠久历史的代码模式,这些错误表明错误率极高,因此没有任何选择。通过启用,-Wall
您将获得一套更具攻击性的警告,以捕获Clang开发人员在C ++代码中发现的最常见错误。但同时使用这两种方法,
假阳性率仍应保持较低水平。
最后,如果您完全愿意在任何时候都使* 假阳性 * 安静下来,请继续-Wextra
。如果您发现警告捕获了很多实际的错误,但这些警告具有愚蠢或毫无意义的误报,请归档错误。我们一直在努力寻找方法,将越来越多的错误发现逻辑-Wextra
带入-Wall
我们可以避免错误肯定的地方。
许多人会发现这些选择都不适合他们。在Google,-Wall
由于许多现有代码违反了警告,因此我们已关闭了一些警告。即使未通过启用警告,我们也已明确启用了某些警告-Wall
,因为它们对我们而言具有特别高的价值。您的里程会有所不同,但可能会以类似的方式发生变化。启用一些关键警告而不是全部警告通常会好得多
-Wextra
。
我鼓励所有人打开-Wall
任何非遗留代码。对于新代码,这里的警告几乎总是有价值的,并确实使开发代码的经验更好。相反,我鼓励所有人
不要启用以外的标志-Wextra
。如果您发现-Wextra
不包含但对您完全有价值的Clang警告,只需提交一个错误,我们可能会将其放在下方-Wextra
。是否明确启用警告中的某些子集将在-Wextra
很大程度上取决于您的代码,您的编码风格以及维护该列表是否比修复由覆盖的所有内容更容易-Wextra
。
在OP的警告列表(包括-Wall
和-Wextra
)中,只有以下警告未被这两个组覆盖(或默认情况下处于启用状态)。第一组强调为什么过度依赖显式警告标志可能会很糟糕:在Clang 中甚至都没有实现!仅出于GCC兼容性在命令行上接受它们。
-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
还有一些警告,它们在分类上更加不同。这些处理语言的方言变体,而不是儿童车或非越野车代码。除了-Wwrite-strings
,这些都是Clang提供的语言扩展警告。Clang是否警告使用它们取决于扩展的普遍性。Clang旨在实现GCC兼容性,因此在许多情况下,它通过广泛使用的隐式语言扩展而得以缓解。-Wwrite-strings
如对OP所述,它是GCC的兼容性标志,它实际上改变了程序的语义。我对这个标志深表遗憾,但是由于它的遗产,我们必须予以支持。
-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
或-Wextra
不总是很清楚的原因。对于许多的这些,其实都是基于GCC警告(-Wconversion
,
-Wshadow
,等),因此锵试图模仿GCC的行为。我们正在将其中的一些细分为更细粒度和有用的警告。然后,那些人更有可能成为高层警告组之一。也就是说,要提一个警告,范围-Wconversion
是如此之广,以至于在可预见的未来,它很可能仍将是其自己的“顶级”类别。海湾合作委员会拥有的其他一些警告,但其价值低,假阳性率高,可能会被归类为类似的无人区。
为什么不在大型存储桶之一中的其他原因包括简单的错误,非常明显的假阳性问题以及开发中的警告。我将研究可以识别的错误的归档。它们最终都应该迁移到适当的大存储桶标志中,或者从Clang中删除。
我希望这可以澄清Clang的警告情况,并为那些试图为其使用或公司使用选择警告的人提供一些见识。