启用详细的 g++ 警告标志

138

通常在使用 gcc 编写 C 代码时,我会使用以下一组警告标志(从多个来源痛苦地汇编而来):

-Wall -Wextra -Wformat-nonliteral -Wcast-align -Wpointer-arith -Wbad-function-cast \
-Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations -Winline -Wundef \
-Wnested-externs -Wcast-qual -Wshadow -Wwrite-strings -Wno-unused-parameter \
-Wfloat-equal -pedantic -ansi

我会使用这套警告标志来构建(至少我的调试版本),并尽可能修复所有问题(通常是全部)。仅在它们不相关或无法修复时,才删除标志(几乎从不发生)。有时,如果我必须离开编译过程,我还会添加-Werror

我刚开始学习C++(是的,我落后15年了),我想一开始就走在正确的道路上。

我的问题是:是否有人有类似的预编译完整的C++警告标志集合在g++下?(我知道其中许多将是相同的。)


88
既然gcc已经决定公然“说谎”关于-Wall选项,那么它需要的是一个-Wbloody_everything标志 :-) (注:这句话意思是希望gcc提供一个更全面的警告标志以替代-Wall,因为-Wall并不能覆盖所有可能存在的问题) - paxdiablo
你可以将你的问题标记为重复,但你也可以将你最后的编辑作为答案,因为你实际上已经回答了你的问题。我很乐意投票支持它 :) - ereOn
哦,好主意!我不能在两天内接受,但是也许其他人会在这段时间想出更多的标志。 - Sdaz MacSkibbons
6
OP和@paxdiablo:GCC 一直以来都拒绝 这种事情,但是在Clang中可以通过-Weverything使用。我读过,甚至包括Clang++的开发人员也有点担心用户打开它;显然,它只是为内部开发使用而设计的。然而,这毫无意义,因为打开-Weverything可能是发现你之前不知道的潜在有用的警告的最佳方式。 - Kyle Strand
2
OP和@paxdiablo,现在有一种方法可以找出给定GCC版本的完整警告列表:https://github.com/barro/compiler-warnings - Kyle Strand
1
可能是如何打开(字面上)GCC的所有警告?的重复问题。 - Ciro Santilli OurBigBook.com
5个回答

158
我找到了最小化的包含项,可以获得最高级别警告。然后我从列表中移除一些我认为并没有实际表示发生了问题的警告,或者有太多错误警报以至于无法在实际构建中使用。我对我排除的每个警告进行了注释,这是我建议的最终警告集合:

-pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Werror -Wno-unused

存在疑问的警告:

  • 我包含-Wno-unused,因为我经常有一些变量我知道将来会用到它们,但目前还没有编写功能。消除关于这一点的警告允许我按照我喜欢的方式书写,偶尔推迟事物的实现。为确保没有遗漏,偶尔关闭警告是很有用的。

  • -Wdisabled-optimization似乎是一个强烈的用户首选项。我刚刚添加了这个警告到我的构建中(仅用于优化构建,显然),它没有发现任何问题,因此对于我的编码方式来说,这似乎不是特别啰嗦的警告。虽然触发该警告的代码并不一定是错误的,但我认为应该与我的工具合作而不是反抗它们。如果gcc告诉我无法根据我编写的方式优化代码,那么我应该考虑重新编写代码。我怀疑触发该警告的代码可能受益于更模块化处理,因此尽管代码在技术上可能没有问题,但从风格上看可能是有问题的。

  • -Wfloat-equal会发出有关安全等式比较的警告(特别是与非计算值-1的比较)。我代码中使用这种警告的例子是我有一个浮点向量。我遍历这个向量,并且有一些元素我还不能确定它们应该是什么,所以我将它们设置为-1.0f(因为我的问题只使用正数,-1不在定义域内)。稍后我会更新-1.0f值。很难采用不同的操作方法。我怀疑大多数人没有这个问题,并且在浮点数中比较精确数字可能是错误的,因此我将其包含在默认列表中。

  • -Wold-style-cast在我使用的库代码中有很多误报。特别是在网络通信中使用的htonl函数族以及我正在使用的Rijndael(AES)加密实现中有旧式转换被警告。我打算替换掉它们,但我不确定代码中是否还有其他会引起警告的内容。大多数用户应该默认开启此选项。

  • -Wsign-conversion有一些误报(几乎没有上榜)。在我的代码中将其打开会产生大量警告(100+)。几乎所有警告都是无意义的。然而,为了我的特定问题域,我通常会因为大量整数除法而使用无符号值,从而获得轻微的效率提升。我牺牲了这个效率,因为我担心将有符号整数提升为无符号整数然后进行除法运算(与加法、减法和乘法不同,这是不安全的)。打开此警告允许我安全地将大多数变量更改为无符号类型,并在其他一些地方添加一些转换。目前使用起来有点困难,因为警告并不那么智能。例如,如果您执行unsigned short + (整数常量表达式),则该结果会隐式提升为int。然后,如果您将该值分配给unsignedunsigned short,它会警告可能存在符号问题,即使它是安全的。这绝对是几乎所有用户最可选的警告。

  • -Wsign-promo:参见-Wsign-conversion

  • -Wswitch-default 似乎毫无意义(如果您已经明确列出了所有可能性,您并不总是需要一个默认情况)。但是,打开此警告可以强制执行一些可能是个好主意的东西。对于那些您明确想忽略除了列出的可能性之外的所有内容的情况(但其他数字是可能的),请添加 default: break; 以使其明确。如果您明确列出了所有可能性,则打开此警告将有助于确保您放置了像 assert (false) 这样的东西,以确保您实际上已经覆盖了所有可能的选项。它允许您明确指定问题域,并在编程上强制执行。但是,在任意地方粘贴 assert (false) 是不好的。这比忽略默认情况要好,但是与 assert 一般一样,在发布版本中它是不起作用的。换句话说,您不能依赖它验证从网络连接或数据库等不完全控制的源获得的数字。处理这种情况的最佳方式是使用异常或提前返回(但仍需要您有一个默认情况)。

  • -Werror 对我来说很重要。在多线程构建和多个目标的大量代码编译时,警告很容易被忽略。将警告转化为错误可以确保我注意到它们。

然后还有一组警告,它们未包含在上述列表中,因为我认为它们无用。以下是这些警告及其原因的评论:

不包括在默认列表中的警告:

  • -Wabi 不需要,因为我没有将不同编译器的二进制文件合并在一起。我尝试使用它进行编译,但它并没有触发,所以似乎不需要写得过于冗长。

  • -Waggregate-return不是我认为的错误。例如,当在类向量上使用基于范围的for循环时触发。返回值优化应该能够处理任何负面影响。

  • -Wconversion 在以下代码上触发警告:short n = 0; n += 2; 隐式转换为int会在转换回其目标类型时导致警告。

  • -Weffc++ 如果不是所有数据成员都在初始化列表中初始化,则会包含警告。我故意不在许多情况下这样做,因此警告集太杂乱无用。不过,有时候打开它并扫描其他警告很有帮助(例如基类非虚拟析构函数)。这将作为一组警告(如-Wall)而不是一个单独的警告更有用。

  • -Winline被省略,因为我不使用关键字inline进行优化,仅用于在头文件中定义函数。我不在意优化器是否实际内联它。如果不能内联在类体中声明的函数(例如空虚拟析构函数),此警告也会发出投诉。

  • -Winvalid-pch被省略,因为我不使用预编译头文件。

  • -Wmissing-format-attribute未使用,因为我不使用gnu扩展。对于-Wsuggest-attribute等几个警告也是如此。

  • 可能值得注意的是缺少-Wno-long-long,我没有需要它。我使用-std=c++0x(在GCC 4.7中使用-std=c++11),其中包括long long整数类型。那些停留在C++98/C++03上的人可以考虑将其从警告列表中排除。

  • -Wnormalized=nfc已经是默认选项,并且看起来是最好的。

  • -Wpadded偶尔会打开以优化类的布局,但不会保留,因为并非所有类都有足够的元素可以去除末尾的填充。理论上,我可以获取一些额外的变量“空闲”,但这不值得维护的额外工作(如果我的类大小发生了更改,则不容易删除先前的自由变量)。

  • -Wstack-protector未使用,因为我不使用-fstack-protector

  • -Wstrict-aliasing=3是由-Wall打开的,是最准确的,但看起来级别1和2会给出更多警告。从理论上讲,较低级别的警告更“强烈”,但代价是更多的误报。我的测试代码在所有三个级别下都编译干净。

  • -Wswitch-enum不是我想要的行为。我不想显式处理每个switch语句。如果语言有一些机制可以激活指定的switch语句(以确保将来对枚举的更改在需要处理的所有位置处处理),那将很有用,但对于“全有或全无”的设置来说,这太过了。

  • -Wunsafe-loop-optimizations会导致太多的虚假警告。定期应用此功能并手动验证结果可能是有用的。例如,在我的代码中,当我循环遍历向量中的所有元素以将一组函数应用于它们时(使用基于范围的for循环),它会生成此警告。它还会针对常量std::string数组的构造函数发出警告(其中用户代码没有循环)。

  • -Wzero-as-null-pointer-constant-Wuseless-cast是仅适用于GCC 4.7的警告,当我转换到GCC 4.7时将添加它们。

作为一些研究结果,我在gcc上提交了一些错误报告/增强请求,所以希望最终能够将“不包括”列表中的更多警告添加到“包括”列表中。此列表包括本主题中提到的所有警告(还有一些额外的)。这篇文章中没有明确提到的许多警告都作为我提到的另一个警告的一部分包括在内。如果有人注意到完全被排除在此文章之外的警告,请告诉我。

编辑:看来我漏掉了几个(现在已经添加了)。实际上,在http://gcc.gnu.org上有第二页,它非常难找到。 通用警告选项C++选项(向下滚动到底部以获取警告)


我并不真正理解你关于-Wswitch-enum的论点,难道不是只需写一个default:分支就可以从技术上禁用特定开关的警告吗? - Predelnik
1
@Predelnik: 这比那更棘手。-Wswitch-enum 会在 switch 中未显式处理每个枚举值时发出警告,而 default 不算显式。另一方面,-Wswitch-default 会在你的 switch 没有 default 语句时发出警告,即使你已经显式覆盖了所有可能的值。 - David Stone
这个列表很棒。顺便说一下,现在有人编写了一个自动化工具来查找给定版本的GCC或Clang的所有警告,并发布了这些列表以供许多编译器版本使用;请参见此处:https://github.com/barro/compiler-warnings - Kyle Strand
我建议添加-Wnon-virtual-dtor,它现在与-Weffc++一起激活,但不会带来-Weffc++的潜在问题。 - FourtyTwo
2
顺便提一句,针对你的“旧库代码”,请使用“-isystem”而不是“-I”,以防止所有这些误报。 - galois
显示剩余7条评论

45

我原来的所有搜索结果都是关于如何“抑制”警告信息的帖子(这实在太可怕了),但我刚刚遇到了这个评论,它有一组美妙的标志(有些不太相关):

与以下内容交叉检查:

http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

-g -O -Wall -Weffc++ -pedantic  \
-pedantic-errors -Wextra -Waggregate-return -Wcast-align \
-Wcast-qual -Wconversion \
-Wdisabled-optimization \
-Werror -Wfloat-equal -Wformat=2 \
-Wformat-nonliteral -Wformat-security  \
-Wformat-y2k \
-Wimplicit  -Wimport  -Winit-self  -Winline \
-Winvalid-pch   \
-Wlong-long \
-Wmissing-field-initializers -Wmissing-format-attribute   \
-Wmissing-include-dirs -Wmissing-noreturn \
-Wpacked  -Wpadded -Wpointer-arith \
-Wredundant-decls \
-Wshadow -Wstack-protector \
-Wstrict-aliasing=2 -Wswitch-default \
-Wswitch-enum \
-Wunreachable-code -Wunused \
-Wunused-parameter \
-Wvariadic-macros \
-Wwrite-strings

所以,我认为那是一个很好的起点。没有意识到这是一个重复问题,但至少它被深深地埋藏了。:-)


1
也许吧,但这似乎会随着版本的变化而改变,并且很可能受到太阳黑子和 RMS 的影响,因此过于明确可能不会有害。无论如何,这是一个很好的起点。 - Sdaz MacSkibbons
3
从对4.5.2的c-opts.c/opts.c进行快速grep查找'case OPT_W',您缺少:strict overflow、undef、strict nul sentinel、normalized、multichar、implicit function declaration、deprecated、endif labels、comments、builtin macro redefined、larger than、larger than eq、abi。真是疯狂,居然没有一个命令行选项可以列出它们。 - Tony Delroy
3
我认为更疯狂的是“-Wall”不像人们期望的那样起作用。但是,谢谢,其中一些看起来非常有用! - Sdaz MacSkibbons
1
禁用警告有其应用场景。毕竟,它们只是“警告”。另一种情况是当您启用一个标志以启用多个警告,但您想要进行选择性操作时。 - Tamás Szelei
@ereOn 这是一个非常好的想法,我已经与文档进行了交叉检查。 - Jared Burrows
1
你如何使用-Waggregate-return?这会在每次使用begin/end()时给我一个警告。 - Flamefire

16

其中一些已经包含在-Wall-Wextra中。

C语言的基本设置如下:

-std=c99 -pedantic -Wall -Wextra -Wwrite-strings -Werror

而对于C++则为:

-ansi -pedantic -Wall -Wextra -Weffc++

(由于-Weffc++有些烦人,因此跳过C++的-Werror)


12
-Werror可以针对特定类型的警告进行禁用,例如:-Werror -Weffc++ -Wno-error=effc++。 - Robert Hensing
3
ansi:在 C 模式下,这相当于 -std=c89。在 C++ 模式下,它相当于 -std=c++98。也就是说,如果您指定了其他的 std,请不要使用 ansi - Sean Breckenridge

2

尝试

export CFLAGS="`gcc --help=warnings | grep '\-W' | awk '{print $1 \" \"}' |
sort | uniq` -pedantic -fdiagnostics-show-option -Werror"

那是一个快速而简单的开始,但肯定需要一些调整;其中一件事是,即使您为您的语言调用了适当的编译器名称(例如C ++的g ++),您仍将收到不适用于该语言的警告(并且编译器会因此而拒绝继续,直到您删除警告)。
另一件事是我添加了-Werror,因为如果您不修复警告,为什么要在意打开它们呢?您还可以从列表中删除警告。(例如,我几乎从不使用-Waggregate-return与C ++。)
有些警告没有其他性能相关选项(-Wstack-protector)将不起作用。-fdiagnostics-show-option和GCC手册是您的好朋友。
顺便说一句,有些警告是互斥的;特别是同时使用-Wtraditional-Wold-style-definition以及-Werror将无法编译。

0
在我的Clion的CmakeLists.txt文件中。
cmake_minimum_required(VERSION 3.13)
project(cpp17)

set(CMAKE_CXX_STANDARD 17)

set(GCC_COVERAGE_COMPILE_FLAGS "-std=c++17 -Wall -Weffc++ -Wno-error=effc++ -pedantic \
 -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-newline-eof  \
-pedantic-errors -Wextra -Waggregate-return -Wcast-align \
-Wcast-qual -Wconversion \
-Wdisabled-optimization \
-Werror -Wfloat-equal -Wformat=2 \
-Wformat-nonliteral -Wformat-security  \
-Wformat-y2k \
-Wimplicit  -Wimport  -Winit-self  -Winline -Winvalid-pch   \
-Wlong-long \
-Wmissing-field-initializers -Wmissing-format-attribute   \
-Wmissing-include-dirs -Wmissing-noreturn \
-Wpacked  -Wpadded -Wpointer-arith \
-Wredundant-decls \
-Wshadow -Wstack-protector \
-Wstrict-aliasing=2 -Wswitch-default \
-Wswitch-enum \
-Wunreachable-code -Wunused \
-Wunused-parameter \
-Wvariadic-macros \
-Wwrite-strings")


set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}" )

add_executable(cpp17 main.cpp)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接