标志以启用全面和详细的 g + + 警告

通常在 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年了) ,我想从正确的方向开始。

我的问题是: 是否有人在 g++下预编译了类似的 C + + 完整警告标志集?(我知道他们中的许多人将会是一样的。)

56288 次浏览

哦,我所有的原始搜索结果都显示了99% 的关于如何使用 压制警告的帖子(足够可怕) ,但是我只是偶然发现了 此评论,它有一组可爱的标志(一些不太相关) :

交叉核对过了:

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

所以,我认为这是一个很好的起点。没意识到这是个骗局,但至少它被深深地埋葬了。:-)

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

C 语言的一个好的基础设置是:

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

以及 C + +

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

(在 C + + 中跳过 -Werror,因为 -Weffc++有一些烦恼)

我查看并发现了应该获得最大警告级别的最小包含集。然后,我从这个列表中删除了一组警告,我觉得这些警告实际上并不表明有什么不好的事情正在发生,或者在实际构建中有太多的假阳性。我评论了为什么我排除的每个人都被排除在外。这是我建议的最后一组警告:

-pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -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.0 f (因为我的问题只使用 正数,-1不在域内) 更新 -1.0 f 值。它不容易借给自己一个不同的 我怀疑大多数人都没有这种操作方法 问题,并比较一个精确的数字在浮点数是 可能是一个错误,所以我将它包含在默认列表中。

  • 在我使用的库代码中,-Wold-style-cast有很多误报。特别是,在网络中使用的 htonl 函数家族,以及我正在使用的 Rijndael (AES)加密实现具有旧式的强制转换,它会警告我。我打算替换这两个,但是我不确定在我的代码中是否还有其他值得抱怨的地方。不过,大多数用户在默认情况下可能应该打开这个选项。

  • -Wsign-conversion是一个艰难的一个(几乎没有使 在我的代码中打开它会产生大量的警告 (100 +)。几乎所有的人都是无辜的。然而,我已经 在我不确定的地方小心地使用有符号整数,尽管 我的特殊问题领域,我通常会得到一个轻微的效率 由于整数的数量很大,因此使用无符号值增加 我知道组织,我牺牲这个效率是因为我担心 关于意外地将有符号整数提升为无符号整数,然后 除法(不像加法、减法和 打开这个警告使我能够安全地更改 我的大部分变量到无符号类型,并在一些 目前有点难以使用,因为警告 是不是很聪明。例如,如果你做 < code > unsignedshort + (整数 常量表达式) ,该结果被隐式提升为 int 然后警告潜在的符号问题,如果你把这个值赋给 unsigned或者 unsigned short即使它是安全的 对于几乎所有的用户来说,这绝对是最可选的警告

  • 参见 -Wsign-conversion

  • -Wswitch-default看起来毫无意义(你并不总是想要一个默认值 如果你已经显式地枚举了所有的可能性), 打开这个警告可以强制执行一些可能是好的 如果你明确地想要忽略所有的东西,除了 列出的可能性(但其他数字是可能的) ,然后把 如果显式枚举 所有的可能性,然后打开这个警告将有助于确保 你放一些类似于断言(false)的东西来确保你已经 实际上涵盖了所有可能的选项 问题的域是什么,并以编程方式强制执行。 但是,在仅仅粘贴断言(false)时,您必须非常小心 总比对默认情况什么都不做要好,但是 和通常的断言一样,它在发布版本中不起作用 单词,你不能依赖它来验证你从中得到的数字, 比方说,一个网络连接或数据库,你没有绝对的 异常或提前返回是最好的方法 处理这个问题(但仍然需要有默认情况!)

  • -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级给出了更多的警告 一个较低的水平是一个“更强”的警告,但它的代价是 更多的假阳性。我自己的测试代码编译干净下所有3 水平

  • -Wswitch-enum不是我想要的行为,我不想处理 每个 switch 语句都要明确 有一些机制来激活指定的开关语句 (以确保将来对枚举的更改可以在任何地方处理 但对于一个“要么全有,要么全无”的人来说,这有点过头了 设置

  • 造成太多虚假的警告 定期应用这个方法并手动验证 作为一个例子,它在我的代码中生成了这个警告 循环遍历向量中的所有元素,以将一组函数应用于 (使用基于范围的 for 循环) 字符串的 const 数组的构造函数(其中这是 no 在用户代码中循环)。

  • -Wzero-as-null-pointer-constant-Wuseless-cast是 GCC-4.7-only 警告,我将在转换到 GCC 4.7时添加此警告。

作为这项研究的结果,我已经在 gcc 提交了一些 bug 报告/增强请求,所以希望我最终能够在“包含”列表中添加更多“不包含”列表中的警告。这个列表包含了本帖中提到的所有警告(另外我想还有一些)。在这篇文章中没有明确提到的许多警告都包含在我提到的另一个警告中。如果有人注意到任何被完全排除在本帖之外的警告,请让我知道。

编辑: 看起来我错过了几个(我现在已经添加了)。实际上,在 http://gcc.gnu.org上还有一个隐藏得很好的第二页。一般警告选项和 < a href = “ http://gcc.gnu.org/onlinedocs/gcc/C _ 002b _ 002b-Diect-Options.html # C _ 002b _ 002b-Diect-Options”rel = “ noReferrer”> C + + options (向下滚动到底部查看警告)

试试看

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

这是一个快速而肮脏的开始,肯定需要一些调整; 首先,即使你用你的语言的适当名称来称呼编译器(例如,用于 C + + 的 g++) ,你也会得到不适用于该语言的警告(编译器会摊开双手,拒绝继续,直到你删除警告)。

另一件事是我在 -Werror中添加的,因为如果不修复警告,为什么要关心打开它们?还可以从列表中删除警告。(例如,我几乎从不在 C + + 中使用 -Waggregate-return。)

如果没有其他与性能相关的选项(-Wstack-protector) ,有些警告将不起作用。 -fdiagnostics-show-option和 GCC 手册是您的朋友。

顺便说一下,有些警告是相互排斥的; 特别是使用 -Wtraditional-Wold-style-definition以及 -Werror,将不能编译。

在我的 Clion 的 CakeLists.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)