Note: This blog post was written for GCC 7. Later versions of the compiler may have added some of these warnings to
GCC can warn about questionable constructs in the source code, but most such warnings are not enabled by default – developers need to use the options
-Wall
or -Wextra
.
GCC can warn about questionable constructs in the source code, but most such warnings are not enabled by default – developers need to use the options
-Wall
and -Wextra
to get all generally useful warnings. There are many additional warning options that are not enabled by -Wall
-Wextra
as they may produce too many false positive warnings or be targeted to a specific obscure use case, but I think a few of them (listed below) may be useful for general use.
-Wduplicated-cond
Warn about duplicated condition in if-else-if chains, such as
int foo(int a) { int b; if (a == 0) b = 42; else if (a == 0) b = 43; return b; }Note:
-Wduplicated-cond
was added in GCC 6.
-Wduplicated-branches
Warn when an if-else has identical branches, such as
int foo(int a) { int b; if (a == 0) b = 42; else b = 42; return b; }It also warns for conditional operators having identical second and third expressions
int foo(int a) { int b; b = (a == 0) ? 42 : 42; return b; }Note:
-Wduplicated-branches
was added in GCC 7.
-Wlogical-op
Warn about use of logical operations where a bitwise operation probably was intended, such as
int foo(int a) { a = a || 0xf0; return a; }It also warns when the operands of logical operations are the same
int foo(int a) { if (a < 0 && a < 0) return 0; return 1; }Note:
-Wlogical-op
was added in GCC 4.3.
-Wrestrict
Warn when the compiler detects that an argument passed to a
restrict
or __restrict
qualified parameter alias with another parameter.void bar(char * __restrict, char * __restrict); void foo(char *p) { bar(p, p); }Note:
-Wrestrict
was added in GCC 7.
-Wnull-dereference
Warn when the compiler detects paths that dereferences a null pointer.
void foo(int *p, int a) { int *q = 0; if (0 <= a && a < 10) q = p + a; *q = 1; // q may be NULL }Note:
-Wnull-dereference
was added in GCC 6.
-Wold-style-cast
Warn if a C-style cast to a non-void type is used within a C++ program.
Note:
int *foo(void *p) { return (int *)p; }Note:
-Wold-style-cast
was added before GCC 3.Note:
-Wold-style-cast
is only available for C++.
-Wuseless-cast
Warn when an expression is cast to its own type within a C++ program.
Note:
int *foo(int *p) { return static_cast<int *>(p); }Note:
-Wuseless-cast
was added in GCC 4.8.Note:
-Wuseless-cast
is only available for C++.
-Wjump-misses-init
Warn if a
Note:
goto
statement or a switch
statement jumps forward across the initialization of a variable, or jumps backward to a label after the variable has been initialized.int foo(int a) { int b; switch (a) { case 0: b = 0; int c = 42; break; default: b = c; // c not initialized here } return b; }Note:
-Wjump-misses-init
was added in GCC 4.5.Note:
-Wjump-misses-init
is only available for C – jumping over variable initialization is an error in C++.
-Wdouble-promotion
Warn when a value of type
Floating point constants have the type
Note:
float
is implicitly promoted to double
.Floating point constants have the type
double
, which makes it easy to accidentally compute in a higher precision than intended. For example,float area(float radius) { return 3.14159 * radius * radius; }does all the computation in
double
precision instead of float
. There is normally no difference in performance between float
and double
for scalar x86 code (although there may be a big difference for small, embedded, CPUs), but double
may be much slower after vectorization as only half the number of elements fit in the vectors compared to float
values.Note:
-Wdouble-promotion
was added in GCC 4.6.
-Wshadow
Warn when a local variable or type declaration shadows another variable, parameter, type, or class member.
The
Note:
int result; int foo(int *p, int len) { int result = 0; // Shadows the global variable for (int i = 0; i < len; i++) result += p[i]; return result; }Note:
-Wshadow
was added before GCC 3.
-Wformat=2
The -Wformat
option warns when calls to printf
, scanf
, and similar functions have an incorrect format string or when the arguments do not have the correct type for the format string. The option is enabled by -Wall
, but it can be made more aggressive by adding -Wformat=2
which adds security-related warnings. For example, it warns for#include <stdio.h> void foo(char *p) { printf(p); }that may be a security hole if the format string came from untrusted input and contains ‘
%n
’.Note:
-Wformat=2
was added in GCC 3.0.
It would be useful to know which gcc version is required for each of this flag.
ReplyDeleteIndded. Also some of them can only be applied to gcc and others only to g++.
DeleteI was a bit lazy when I wrote the blog post... Sorry!
DeleteBut I have now added information about when the options were introduced, and which are restricted to C/C++.
Great post! I wonder why -Wnull-dereference is not enabled. It is such a common mistake!
ReplyDeleteThere are some cases where it can warn incorrectly. It does not happen too often, but those cases often need big changes in the code's structure for the warning to disappear (i.e. it is not enough to just initialize a variable as for the incorrect warnings you may get from \(\verb!-Wuninitialize!\)).
DeleteThanks!
ReplyDeleteThere is the very useful -Wmisleading-indentation
ReplyDeleteYes, it is useful – but it is already included in \(\verb!-Wall!\).
DeleteVery interesting! Some of these warnings are more what one would expect from static analysis, rather than from the compiler.
ReplyDeleteOne caution, though -- at least in my testing -Wshadow is pretty much unusable on gcc because of the many false positives. clang seems to do a much better job. I wrote about this at http://btorpey.github.io/blog/2015/03/17/shadow/
I have not had any such problems in the code I work with, but I can see how this may be a problem for large code bases...
DeleteGCC 7 introduced a modifier to the warning option, so \(\verb!-Wshadow=local!\) does only warn when a local variable shadows another local variable or parameter. This solves the problem Linus complained about, but it fails to warn about your example...
Thanks! These are some nice examples. I've been using a slew extra GCC warnings for 5 years or so by now, so its nice surprise to find more.
ReplyDeleteDo you ever/selectively promote warnings to warnings to errors?
I usually promote most of "definitely undefined behavior"-warnings to errors, and I'm considering promoting -Wduplicated-cond and
-Wduplicated-branches to errors.
For reference, these are my usual warning flags:
-Wno-variadic-macros -W -Wpedantic -Wextra -Wall -Wcast-align -Wcast-qual -Wstrict-aliasing=2 -Wframe-larger-than=32768 -Wno-strict-overflow -Wsync-nand -Wtrampolines -Wsign-compare -Werror=float-equal -Werror=missing-braces -Werror=init-self -Werror=logical-op -Werror=write-strings -Werror=address -Werror=array-bounds -Werror=char-subscripts -Werror=enum-compare -Werror=implicit-int -Werror=empty-body -Werror=main -Werror=aggressive-loop-optimizations -Werror=nonnull -Werror=parentheses -Werror=pointer-sign -Werror=return-type -Werror=sequence-point -Werror=uninitialized -Werror=volatile-register-var -Werror=ignored-qualifiers -Werror=missing-parameter-type -Werror=old-style-declaration -Wno-error=maybe-uninitialized -Wno-unused-function -Wodr -Wformat-signedness -Wsuggest-final-types -Wsuggest-final-methods -Wno-ignored-attributes -Wno-missing-field-initializers -Wshift-overflow=2 -Wduplicated-cond \
-Wduplicated-branches -Werror=restrict -Wdouble-promotion -Wformat=2
I don't see -Wlogical-op in GCC 4.7 ... was it actually introduced in GCC 6, not 4.3 ?
ReplyDeletemay it be problematic to include warnings that are not supported by the host ? Or will they just be ignored ?
ReplyDeleteIt is problematic. GCC reports an error for unknown warning options.
DeleteThank you for this great post.
ReplyDeleteAccording to https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html the option "-Wrestrict" is already enabled by "-Wall":
"The -Wrestrict option detects some instances of simple overlap even without optimization but works best at -O2 and above. It is included in -Wall."
The blog post was written for GCC 7 (where -Wall does not enable -Wrestrict). I had not noticed that it was added to GCC 8, but I have updated the blog post with a note about compiler versions. Thanks!
Delete