gcc is really great tool for finding errors in your code, but it helps to pass it the right flags to make sure it doesn’t forget to tell you about them. I would always recommend enabling -Wall
on whatever code you build, and if possible -Werror
. However, sometimes this is not enough, for example, the code below has a subtle bug:
int func(char *buf) { int i; for (i = 0; i < 16; i++) { if (buf[i] != 0xff) return 1; } return 0; }
If we compile this with gcc:
# gcc -O2 -S -Wall func.c
The assembly output is given below.
.text .globl func .type func, @function func: movl $1, %eax ret
It looks like all our code has disappeared! gcc has taken advantage of the fact the type information in the code to decide that the loop can be elided completely and optimized it out. This is because c
is a pointer to signed char (on x86_64, other architectures define char as unsigned and will not optimize this out) and 0xff
is an integer constant that will not fit in a signed char, hence the comparison will never be true and the loop has no effect.
This behaviour is perfectly fine with respect to the C standard, however I do think gcc should warn when it is performing this type of transformation. If we build with clang (the LLVM C compiler), we get:
# clang -O2 -S func.c func.c:8:14: warning: comparison of constant 255 with expression of type 'char' is always true [-Wtautological-constant-out-of-range-compare] if (buf[i] != 0xff) ~~~~~~ ^ ~~~~ 1 warning generated.
Which seems much more appropriate than silence. gcc can be fixed to generate an error with -Wextra
or -Wtype-limits
:
gcc -O2 -S -Wall -Wextra func.c func.c: In function ‘func’: func.c:8:3: warning: comparison is always true due to limited range of data type [-Wtype-limits]
-Wextra
can be problematic however as it contains a number of warnings that are quite noisy and uninteresting, for example -Wunused-parameter
, so you may have to experiment a little to apply it to your codebase.