I often hear that when compiling C and C++ programs I should "always enable compiler warnings". Why is this necessary? How do I do that?
Sometimes I also hear that I should "treat warnings as errors". Should I? How do I do that?
I often hear that when compiling C and C++ programs I should "always enable compiler warnings". Why is this necessary? How do I do that?
Sometimes I also hear that I should "treat warnings as errors". Should I? How do I do that?
You should always enable compiler warnings because the compiler can often tell you what's wrong with your code. To do this, you pass
-Wall -Wextra
to the compiler.You should usually treat warnings as errors because the warnings usually signify that there's something wrong with your code. However, it's often very easy to ignore these errors. Therefore, treating them as errors will cause the build to fail so you can't ignore the errors. To treat warnings as errors, pass
-Werror
to the compiler.Some warning may mean possible semantic error in code or possible UB. E.g.
;
afterif()
, unused variable, global variable masked by local, or comparison of signed and unsigned. Many warnings are related to static code analyzer in compiler or to breaches of ISO standard detectable at compile time, which "require diagnostics". While those occurrences may be legal in one particular case, they would be result of design issues most of time.Some compilers, e.g. gcc, have a command line option to activate "warnings as errors" mode, it's a nice , if cruel, tool to educate novice coders.
As someone who works with legacy embedded C code, enabling compiler warnings has helped show a lot of weakness and areas to investigate when proposing fixes. In gcc utilizing
-Wall
and-Wextra
and even-Wshadow
have become vital. I'm not going to go every single hazard, but I'll list a few that have popped up that helped show code issues.Variables being left behind
This one can easily point to unfinished work and areas that might not be utilizing all of the passed variables which could be an issue. Let's look at a simple function that may trigger this:
Just compiling this without -Wall or -Wextra returns no issues. -Wall will tell you though that
c
is never used:-Wextra will also tell you that your parameter b doesn't do anything:
Global Variable shadowing
This one bit hard and did not show up until
-Wshadow
was used. Let's modify the example above to just add, but there just happens to be a global with the same name as a local which causes a lot of confusion when trying to use both.When -Wshadow was turned on, it's easy to spot this issue.
Format strings
This doesn't require any extra flags in gcc, but it has still be the source of problems in the past. A simple function trying to print data, but has a formatting error could look like this:
This doesn't print the string since the formatting flag is wrong and gcc will happily tell you this is probably not what you wanted:
These are just three of the many things the compiler can double check for you. There are a lot of others like using an uninitialized variable that others have pointed out.
You should definitely enable compiler warnings as some compilers are bad at reporting some common programming mistakes, including the following:-
-> initialise a variable gets forgotten -> return a value from a function get missed -> the simple arguments in printf and scanf families not matching the format string a function is used without being declared beforehand, though happens in c only
So as these functions can be detected and reported, just usually not by default; so this feature must be explicitly requested via compiler options.
Treating warnings as errors is just a mean of self-discipline: you were compiling a program to test that shiny new feature, but you can't until you fix the sloppy parts. There is no additional information
Werror
provides, it just sets priorities very clearly:It's really the mindset that's important, not the tools. Compiler diagnostics output is a tool. MISRA (for embedded C) is another tool. It doesn't matter which one you use, but arguably compiler warnings is the easiest tool you can get (it's just one flag to set) and the signal to noise ratio is very high. So there's no reason not to use it.
No tool is infallible. If you write
const float pi = 3.14;
, most tools won't tell you that you defined π with a bad precision which may lead to problems down the road. Most tools won't raise an eyebrow onif(tmp < 42)
, even if it's commonly known that giving variables meaningless names and using magic numbers is a way to disaster in big projects. You have to understand that any "quick test" code you write is just that: a test, and you have to get it right before you move on to other tasks, while you still see its shortcomings. If you leave that codes as is, debugging if after you spend two months adding new features will be significantly harder.Once you get into the right mindset, there is no point in using
Werror
. Having warnings as warnings will allow you to take an informed decision whether it still makes sense to run that debug session you were about to start, or to abort it and fix the warnings first.Ignoring warnings means you left sloppy code that not only could cause problems in the future for someone else, but also will make important compile messages less noticed by you. The more compiler output, the less anyone will notice or bother. Cleaner the better. It also means you know what you are doing. Warnings are very unprofessional, careless, and risky.