如何打开(字面上)所有GCC警告?


194

我真的要启用GCC的所有警告。(您会认为这很容易...)

  • -Wall可能认为可以解决问题,但不能!还需要-Wextra

  • -Wextra可能认为可以解决问题,但不能!并非所有此处列出的警告(例如-Wshadow)都已启用。而且我仍然不知道这个清单是否全面。

我如何告诉GCC启用(如果不是,则不是,否则为!)所有警告?


27
@Arafangion:我不明白这个问题的“不清楚之处”,是的,我想打开适用于我的代码的所有警告,无论它有多讨厌。作为原因,它非常简单:我发现-Wall或-Wextra未打开的一些警告很有帮助,因此,我想尝试其余的内容,看看是否可以改进我的代码。就这么简单。
2012年

12
@JoachimPileborg:“您希望编译器警告什么?” 潜在的错误和/或不良风格?我的意思是,如果我知道所有确切的警告,则只需手动将其打开即可,而无需提出问题。如果答案确实是“您必须查看源代码才能找到所有代码”,那么请将其发布为答案!
user541686

56
clang 3.1提供-Weverything
亚历山大·哈梅兹

5
@Arafangion好吧,这个问题被标记为C ++,所以... :)
某些程序员花了

5
@JoachimPileborg现在(终于)有了一种自动从源中提取警告的方法:github.com/barro/compiler-warnings
凯尔·斯特兰德

Answers:


129

你不能

GCC 4.4.0的手册仅适用于该版本,但确实列出了4.4.0的所有可能的警告。但是,它们并非全部位于您链接到的页面上,例如,某些特定于语言的选项位于C ++选项或Obj-C选项的页面上。要找到它们,最好查看“ 选项摘要”

开启 所有内容将包括-Wdouble-promotion仅与具有32位单精度浮点单元的CPU相关的功能,该单元float在硬件中实现,但double在软件中仿真。像double使用软件仿真那样进行计算会比较慢。这与某些嵌入式CPU有关,但与具有64位浮点硬件支持的现代台式机CPU完全无关。

另一个通常不有用的-Wtraditional警告是,它警告格式完美的代码在传统C(例如"string " "concatenation")或ISO C函数定义中具有不同的含义(或不起作用)!您真的关心与30年历史的编译器的兼容性吗?您真的想要写警告int inc(int i) { return i+1; }吗?

我认为-Weffc++太吵了,没用,它基于过时的有效C ++第一版,并警告那些完全有效的C ++构造(并且在本书的更高版本中对其准则进行了更改。)我不想成为警告我尚未std::string在构造函数中初始化成员;它有一个默认构造函数,它完全符合我的要求,为什么我要编写该函数m_str()来调用它呢?-Weffc++有用的警告对于编译器来说很难准确地检测(给出错误的否定),而那些无用的警告(例如,显式初始化所有成员)只会产生过多的噪音,从而产生错误的肯定。

吕克·丹顿(Luc Danton)提供了 很好的无用警告示例-Waggregate-return因为对于C ++代码几乎毫无意义。

即你不是真的想要 所有警告,只是以为自己想要。

浏览手册,阅读有关内容,确定您可能要启用的内容,然后尝试使用它们。阅读编译器手册是一件好事无论如何, TM,捷径并启用您不理解的警告不是一个好主意,尤其是在避免RTFM的情况下。

刚打开一切的人可能是因为他们无能为力,或者是一个尖顶的老板说“没有警告”。

有些警告很重要,有些则不重要。您必须加以区分,否则您会弄乱程序。例如,考虑-Wdouble-promotion。如果您在嵌入式系统上工作,则可能需要这样做。如果您使用的是台式机系统,则可能不需要。而你想要-Wtraditional吗?我对此表示怀疑。

编辑:另请参阅-Wall-all以启用所有警告作为WONTFIX关闭的。

编辑2:针对DevSolar的投诉,makefile需要根据编译器版本使用不同的警告,如果-Wall -Wextra不合适,则使用特定于编译器和特定于版本的CFLAGS并不困难:

compiler_name := $(notdir $(CC))
ifeq ($(compiler_name),gcc)
compiler_version := $(basename $(shell $(CC) -dumpversion))
endif
ifeq ($(compile_name),clang)
compiler_version := $(shell $(CC) --version | awk 'NR==1{print $$3}')
endif
# ...
wflags.gcc.base := -Wall -Wextra
wflags.gcc.4.7 := -Wzero-as-null-pointer-constant
wflags.gcc.4.8 := $(wflags.gcc.4.7)
wflags.clang.base := -Wall -Wextra
wflags.clang.3.2 := -Weverything
CFLAGS += $(wflags.$(compiler_name).base) $(wflags.$(compiler_name).$(compiler_version))

38
“仔细阅读手册,了解它们,然后决定您要启用的内容,然后尝试使用它们。” 这里的问题是您遗漏的步骤:“重新访问每个编译器版本的手册,并调整警告列表,因为它们一直在变化。使Makefile检查确切的编译器版本,并使用其他警告列表为他们每个人。” 我们拥有维护人员维护的优化级别;为什么他们不为提供相同的警告服务而烦恼呢?
DevSolar

17
@JonathanWakely:我有我的项目,而GCC不在其中。我指出了他们产品的弱点。他们要么修复它,要么接受不这样做的责任,但是OSS不能由我来为他们修复。
DevSolar

14
@JonathanWakely:“如果您想要一些东西,就索要它,不要管它。” -我没有义务为了批评它而参与GCC项目,尤其是如果#31573已经被标记为WONTFIX的话,尤其如此。这使该主题从“询问”变成了“询问”。
DevSolar

61
-Weverything我认为,这是比不提供此类选择的gcc战略更好的解决方案。我将此标志与clang一起使用,因为我的理念是默认情况下我希望所有警告都处于打开状态(因为有人认为添加到编译器中会很有帮助),如果我不喜欢它,则专门关闭该警告。关键是您不知道不会触发的警告,但是您确实知道不希望触发的警告,因此很容易将其关闭。
大卫·斯通

17
@JonathanWakely是的,但是他们很微不足道。查看哪些警告可能与您的代码相关的最简单方法是查看您的代码触发了哪些警告。届时,在决定是否禁用警告之前,您可以查看潜在危险代码的实际相关示例。使用Clang的-Weverything选项可以轻松完成此操作,但使用GCC则不可能。
Kyle Strand

71

我同意先前的回答,即从字面上启用所有警告可能无益,但是GCC确实提供了一种实现此目的的合理方便的方法。命令

gcc -Q --help=warning

提供所有受支持的警告选项的列表,以及有关它们是否处于活动状态的信息。这可以通过方式来找出哪个选项(不)例如通过启用-Wall-Wextra

gcc -Wall -Wextra -Q --help=warning

要启用所有警告,您可以使用一些正则表达式提取命令行参数

gcc -Q --help=warning | sed -e 's/^\s*\(\-\S*\)\s*\[\w*\]/\1 /gp;d' | tr -d '\n'

对于我当前的GCC,这给出了:

-Wabi -Wabi标签-Waddress -Waggregate返回-Waggressive循环优化-Waliasing -Walign-commons -Wampersand -Warray-bounds -Warray-temporaries -Wassign-intercept -Wattributes -Wbad-function-cast -Wbool-compare -Wbuiltin-macro-redefined -Wc ++-compat -Wc ++ 0x-compat -Wc ++ 14-compat -Wc-binding-type -Wc90-c99-compat -Wc99-c11-compat -Wcast-align -Wcast-qual -Wchar下标-W字符截断-Wchkp -Wclobbered -Wcomment -Wcompare-reals -W有条件支持-Wconversion -Wconversion-extra -Wconversion-null -Wcoverage-mismatch -Wcpp -Wctor-dtor-privacy -Wdate-time -Wdeclaration -声明后-Wdelete不完整-Wdelete-non-virtual-dtor -Wdeprecated -Wdeprecated-clarifications -Wdesignated-init -Wdisabled-optimization -Wdiscarded-array-qualifiers -Wdiscarded-qualifiers -Wdiv-by-零-Wdouble-promotion -Weffc ++-虚空的身体-Wendif-labels -Wenum-compare -Wextra -Wfloat-equal -Wformat-contains-nul -Wformat-extra-args -Wformat-nonliteral -Wformat-security -Wformat-signness -Wformat-y2k -Wformat-zero-length -Wfree -非堆对象-Wfunction消除-Wignored-qualifiers -Wimplicit -Wimplicit-function-clarification -Wimplicit-int -Wimplicit-interface -Wimplicit-procedure -Wincompatible-pointer-types -Winherited-variadic-ctor -Winit-self -Winline -Wint转换-Wint-to-pointer-cast -Wintrinsic-shadow -Wintrinsics-std -Winvalid-Memory-model -Winvalid-offsetof -Winvalid-pch -Wjump-misses-init -Wline-truncation -Wliteral后缀-Wologic -非括号-Wologic-op -Wlong-long -Wmain -Wmay尚未初始化-Wmemset转换后的参数-Wmissing括号-Wmissing-声明-Wmissing-field-initializers -Wmissing-include-dirs -Wmissing-parameter-type -遗忘原型-Wmultichar -Wnarrowing -Wnested-externs -Wnoexcept -Wnon-template-friend -Wnon-virtual-dtor -Wnonnull -Wodr -Wold-style-cast -Wold-style-declaration -Wold-style-definition -Wopenmp-simd -Woverflow -Woverlength-strings -Woverloaded-virtual -Woverride-init -Wpacked -Wpacked-bitfield-compat -Wpapped -Wparentheses -Wpedantic -Wpmf-conversions -Wpointer-arith -Wpointer-sign -Wpointer-to-int-cast -Wpragmas -Wproperty -assign-default -Wprotocol -Wreal-q-constant -Wrealloc-lhs -Wrealloc-lhs-all -Wredundant-decls -Wreorder -Wreturn-local-addr -Wreturn-type -Wselector -Wsequence-point -Wshadow -Wshadow-ivar -Wshift计数负数-Wshift计数溢出-Wsign比较-Wsign促销-Wsize释放-Wsizeof数组参数-Wsizeof-pointer-memaccess -Wstack-protector -Wstrict-null-Sentinel -Wstrict-prototypes -严格选择匹配-Wsuggest-属性=常量-Wsuggest-属性=格式-Wsuggest-属性= noreturn -Wsuggest-属性=纯-Wsuggest-final方法-Wsuggest-final类型-Wsuggest-override -Wsurprising -Wswitch -Wswitch-bool -Wswitch -default -Wswitch枚举-Wsync-nand -Wsynth -Wsystem-headers -Wtabs -Wtarget-lifetime -Wtraditional -Wraditional-conversion -Wtrampolines -Wtrigraphs -Wtype-limits -Wondeclared-selector -Wundef -Wunderflow -Wuninitialized -Wunknown-pragmas -Wunsafe循环优化-Wunsuffixed浮点常量-Wunused -Wunused-但是设置参数-Wunused-但设置变量-Wunused-Dummy参数-Wunused函数-Wunused-label -Wunused-local-defs -无用的宏-无用的参数-无用的结果-无用的值-无用的变量-Wuse-without-only -Wuseless-cast -Wvarargs -Wvariadic-macros -Wvector-operation-performance-Wvirtual-move-assign-Wvla -Wvolatile-register-var -Wwrite-strings -Wzero-null-pointer-constant -Wzerotrip -frequire-return-statement

现在可以用来呼叫GCC,即

gcc $(gcc -Q --help=warning | sed -e 's/^\s*\(\-\S*\)\s*\[\w*\]/\1 /gp;d' | tr -d '\n')

但是请注意,由于某些警告选项仅适用于某些语言(例如C++),因此会产生警告。可以通过使用更多的正则表达式来避免这些问题,以仅包括当前语言允许的选项,或者-Wno-whatever在通话结束时添加适当的选项。


10
恐怕不切实际。Gcc向我显示了来自std lib的警告。
Valentin Heinitz '16

13
@ValentinHeinitz正如我说的,我认为启用所有警告均无济于事,但这就是OP所要求的。但是,我认为通过显式删除其他答案中已经提到的一些有问题的警告(例如,在通话结束时添加相应的-Wno-what-every),可以实际使用。
Haatschii

6
@ValentinHeinitz您可以通过使用-isystem代替-I相关目录来防止gcc对system / std / 3rd-party标头发出警告。
凯尔·斯特兰德

4
这应该是公认的答案,因为这实际上是直接回答问题。
TFuto

16

不可能在所有警告都启用的情况下进行编程(除非您要忽略它们,否则为什么要打扰?)。例如,假设您使用以下标志集:-Wstrict-prototypes -Wtraditional

即使启用了两个警告,以下程序也会抱怨。

/tmp $ cat main.c 
int main(int argc, char **argv) {
    return 0;
}
/tmp $ gcc -Wstrict-prototypes -Wtraditional main.c 
main.c: In function main’:
main.c:1:5: warning: traditional C rejects ISO C style function definitions [-Wtraditional]
 int main(int argc, char **argv) {
     ^

您可能会认为“好吧,那我将使用旧样式的原型”。不,这行不通。

/tmp $ cat main.c 
int main(argc, argv)
    int argc;
    char **argv;
{
    return 0;
}
/tmp $ gcc -Wstrict-prototypes -Wtraditional main.c 
main.c:1:5: warning: function declaration isnt a prototype [-Wstrict-prototypes]
 int main(argc, argv)
     ^

不,不指定任何原型也是错误的,因为编译器也会抱怨。

/tmp $ cat main.c 
int main() {
    return 0;
}
/tmp $ gcc -Wstrict-prototypes -Wtraditional main.c 
main.c:1:5: warning: function declaration isnt a prototype [-Wstrict-prototypes]
 int main() {
     ^

如果在程序中定义任何函数,则不能使用所有标志,因为编译器会抱怨任何可想像的函数定义。

对于C ++,这是可能的(该-Wtraditional标志不存在),并且可以编译非常简单的程序。要启用所有警告,请使用以下警告列表(可能有些警告是重复的,因为我没有费心过滤启用的警告-Wall)。

-Wabi -Wctor-dtor-privacy -Wnon-virtual-dtor -Wreorder -Weffc++ -Wstrict-null-sentinel -Wno-non-template-friend -Wold-style-cast -Woverloaded-virtual -Wno-pmf-conversions -Wsign-promo -Wextra -Wall -Waddress -Waggregate-return -Warray-bounds -Wno-attributes -Wno-builtin-macro-redefined -Wc++0x-compat -Wcast-align -Wcast-qual -Wchar-subscripts -Wclobbered -Wcomment -Wconversion -Wcoverage-mismatch -Wno-deprecated -Wno-deprecated-declarations -Wdisabled-optimization -Wno-div-by-zero -Wempty-body -Wenum-compare -Wno-endif-labels -Wfatal-errors -Wfloat-equal -Wformat -Wformat=2 -Wno-format-contains-nul -Wno-format-extra-args -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wignored-qualifiers -Winit-self -Winline -Wno-int-to-pointer-cast -Wno-invalid-offsetof -Winvalid-pch -Wunsafe-loop-optimizations -Wlogical-op -Wlong-long -Wmain -Wmissing-braces -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wno-mudflap -Wno-multichar -Wnonnull -Wno-overflow -Woverlength-strings -Wpacked -Wpacked-bitfield-compat -Wpadded -Wparentheses -Wpointer-arith -Wredundant-decls -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -Wsign-conversion -Wstack-protector -Wstrict-aliasing=1 -Wstrict-overflow=5 -Wswitch -Wswitch-default -Wswitch-enum -Wsync-nand -Wsystem-headers -Wtrigraphs -Wtype-limits -Wundef -Wuninitialized -Wunknown-pragmas -Wno-pragmas -Wunreachable-code -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wvariadic-macros -Wvla -Wvolatile-register-var -Wwrite-strings

13
直到现在,我一直没有检查过它,但是实际上,这并非不可能...试试int main(int, char **); int main(argc, argv) int argc; char **argv; { (void)argc; (void)argv; return 0; }
user541686

2
即使有了这个微不足道的程序,我仍然可以收到“警告:堆栈使用率为16个字节[-Wstack-usage =]” ;-)
Marc Glisse

7

有人创建了一套工具来确定给定GCC或Clang版本的完整警告集。

对于GCC,从此工具为您的编译器版本提供的完整警告列表中进行复制似乎是确保所有警告均已打开的唯一方法,因为(与Clang不同)GCC不提供。-Weverything

该工具似乎可以解析c.optGCC源代码中的实际文件,因此其结果应该是确定的。

该存储库还包含带有针对大多数GCC和Clang版本(当前为Clang 3.2至3.7和GCC 3.4至5.3)生成的警告列表的文本文件。

https://github.com/barro/compiler-warnings


这就是答案。使用“顶层”列表,并添加顶层上的所有参数(不缩进/嵌套)。github.com/Barro/compiler-warnings/blob/master/gcc/...
水上摩托S型

6

Gcc 4.3+现在有了-Q --help = warnings,甚至可以指定--help = warnings,C来仅打印出与C相关的警告。

我刚刚编写了一个m4模块来利用此功能(也支持clang的-Weverything),请参见 wget_manywarnings.m4

如何使用它非常简单,基本上模块会打开每个警告标志。而且您可以根据需要删除警告-有些警告确实很冗长。例: configure.ac

如果您不使用自动工具,则会在m4模块中找到打开所有禁用警告的代码,这基本上是通过awk传递的gcc调用:

flags="-Wall -Wextra -Wformat=2 "$(gcc -Wall -Wextra -Wformat=2 -Q --help=warning,C|awk '{ if (($2 == "[disabled]" || $2 == "") && $1!~/=/ && $1~/^-W/&& $1!="-Wall") print $1 }'


3

从此页面

请注意,并未暗示某些警告标志-Wall。他们中的一些人警告用户通常认为不会有问题的结构,但有时您可能希望检查一下。其他人则警告某些情况下必须避免的结构或难以避免的结构,并且没有简单的方法来修改代码以抑制警告。其中一些已启用,-Wextra但其中许多必须单独启用。

我想问题是哪个?也许您可以grep该页面以-W开头的所有行,并获得警告标志的完整列表。然后比较这些与列表下-Wall-Wextra。还有-Wpedantic,尽管您显然仍然想变得更加学究=)


“而且我仍然不知道此列表是否完整” ……是的,我当然可以grep该页面,但是问题是,它是否完整?
user541686

1
我不知道...您可能需要浏览GCC源代码。您是想让自己的程序员生活变得非常困难,还是有充分的理由希望看到所有可能的警告?=)
水稻2012年

2
我想看看GCC对我的代码的诊断-我发现它确实很有帮助。但是显然,如果我已经知道所有警告以及哪些警告有用(哪些警告无效),那么就没什么要问的了。除非我尝试使用它们,否则没有真正的方法可以告诉我(例如,我发现阴影之一很有用,因此,并不是因为关闭了它们就没有用)。
user541686

3

而且我仍然不知道这个清单是否全面。

可能是,但唯一全面的列表是编译器的实际来源。但是,GCC 很大!而且我不知道所有命令行参数是集中收集还是分散在多个源文件中。还要注意,有些警告是针对预处理程序的,某些警告是针对实际的编译器的,而某些警告是针对链接器的(这是一个完全独立的程序,位于binutils软件包中),因此很可能会散布开来。


3
我链接到答案中的“ 选项摘要”页面,该页面将所有选项分为一个页面。GCC代码审核政策不允许没有文档的新选项,因此文档应全面。
Jonathan Wakely 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.