Compiler Warnings Part 1 – Treat Them Right

Contents

We often see compiler warnings about pieces of code that have potential problems or poor style. Sometimes they point out code that is actually wrong, so don’t ignore them.

You’ve probably seen already a compiler warning or two during the compilation of C++ code. Chances are that if you work on one of those big ol’ projects, you see hundreds of those warnings every day. After some time you know a few of them. They become an annoying background noise whenever you hit the compile button.

Don’t ignore compiler warnings

Yes, warnings can be annoying. And yes, often, maybe even most times the compiler complains about perfectly valid code that contains no bug. But rest assured, that once every few thousand compiler warnings or so, the compiler actually has a point. We sometimes write code that compiles but does something odd we didn’t intend.

So how do we find that one warning that actually points us to an error? How do we distinguish it from the hundreds of similar warnings where that code is valid? It seems like a waste of time to read through so many warnings, not knowing if they are actual errors. It gets close to impossible if I ask you to do that every time you get a warning during compilation.

Adopt a “no warnings” policy

If we are really honest, there are only two things we can do about compiler warnings. Either we ignore them or we get rid of them completely. Ignoring them means we throw a tool out of the window that can prevent bugs. Can you stand the risk of letting a (serious) bug or two slip through your fingers? Probably not.

“But”, you may say, “if there are only a handful of warnings, I can live with that.” Well, here’s a thing. You probably test your code relatively often (at least I hope so). To do so, you will compile often, which means you will see those warnings often. You’ll start to ignore them. Maybe you’ll notice when you get 6 instead of 5 compiler warnings and analyze the new warning. Will you also notice the 11th warning creeping in? The 20th? The 52nd that hints at an actual bug?

Getting rid of the warnings is the only viable and safe option.

Change your code to get rid of warnings

While there sometimes are situations where we just want the compiler to be silent about a specific warning, the better option is to change the code. If the code is not clear to the compiler, chances are good that it may no be clear to some human readers either. Clarifying your intent in the code often is enough to silence the compiler.

Some compilers may even give you a hint how to fix a certain warning. Let’s pick the often cited warning about assignment in a conditional context:

int a = 3;
int b = 5;

if (a = b) {  //!
  doSomething(); 
}

The CLANG output will look like this:

warning: using the result of an assignment as a condition without parentheses [-Wparentheses] 
if (a = b) { 
    ~~^~~ 

note: place parentheses around the assignment to silence this warning 
if (a = b) { 
      ^ 
    (    ) 

note: use '==' to turn this assignment into an equality comparison 
if (a = b) {
      ^ 
      ==

The second note is for the case which is the reason for this warning: sometimes we write `a = b` when we meant `a == b`. While other compilers simply warn that the assignment we wrote looks odd in that place, CLANG helpfully tries to guess what we could have meant. The first note simply tells us how to fix the warning, if the assignment was actually intended. GCC has the same warning and suggestion for a fix, but without giving us alternatives:

warning: suggest parentheses around assignment used as truth value [-Wparentheses]
if (a = b) {
         ^

I actually like the CLANG output more, because it leads us to actually think about what the right solution may be. This is much better, because we actually might find out that the code has a bug, which we don’t if we automatically apply what ever the compiler suggests.

Think about the causes for compiler warnings Maybe the compiler found a bug for you.

Even if the assignment actually was intended, just applying the compilers suggestion and add another pair of parentheses may not be the right thing to do. From a clean code point of view, we should separate assignment and condition. It is much clearer to have one line for each small task, essentially applying the Single Responsibility Principle on a per-line basis:

a = b;
if (a) {
  doSomething();
}

Don’t fix compiler warnings mechanically, fix them well thought.

Conclusion

Strive to fix all your compiler warnings in a good and clean way. Next week I will write about how to configure our compiler to give us the warnings we need to see.

Previous Post
Next Post

14 Comments




  1. Hi Arne,
    I am a little worried as you are off your usual timeline of posting. Is everything ok.?

    Reply

    1. I guess my question is invalid now:(

      Reply

    2. Hi Simia,
      I’m sorry, I seem to have messed up the scheduled date of yesterday’s post, so it did not show up at the top of the page. It was however published at the usual time, so no worries, everything is OK – and thanks for asking!

      Arne

      Reply

  2. In general, I agree with this article. However, there are cases where the compiler issues warning for valid programming techniques that are used frequently enough that they should be globally disabled. For my code, and Microsoft’s C++ compiler these are 4146, 4201, 4456, 4457, 4459, 4800 and 6246. Those complain about the use of a unary minus with an unsigned field, nameless structs / unions, nested scopes hiding variable names (these are always indexing cases where an indexing variable is defined in a for loop, nested macro code hits this a lot), conversion of non-bool to bool (turning that off by code would be ok, but the warning doesn’t go away). Sometimes they have to be disabled on the command line – 4756 is an example (overflow in constant arithmetic).

    Then there are explicit cases where I disable a warning in a specific stretch of code, again for valid programming techniques, but ones not used much and always with a comment. The warnings are enabled after the code. Examples are 6001 where a precondition prevents the condition and 6297 where the result of the shift and conversion to 64-bits is designed to be correct (and more efficient).

    Warnings are a compiler writer’s best guess as to what is bad code or programming practice, but those ideas don’t always meet reality or the way in which a language like C++ is actually used. There are “undefined” aspects of C/C++ which are really defined for all compilers I have ever used (and defined in the same way). The only reason that they are undefined is to support archaic machines that don’t exist anymore or to make the compiler writer’s job easier.

    Some compiler writer’s assume that you are using a naïve model of arithmetic instead of the actual (and common) hardware model. Right shift damn well better shift a signed value correctly or I won’t use the compiler (it does on every compiler I have ever used).

    Reply

    1. Thanks for your thoughts! Next week I’ll publish part 2 of this article, where I write about this exact topic: telling the compiler what to warn about and when to shut up. Which warnings are valid and which are not is often a matter of style and personal taste and can lead to heated and lengthy discussions.

      Reply

  3. ‘Use of “whatever” is deprecated’

    I see that on big projects where “whatever” is included in a 1000 individual objects, each instance spawning a dozen more warnings.

    OUCH!

    Reply

    1. This is a typical situation to be in when you are maintaining large legacy projects. Sometimes there are ways to get rid of a majority of those deprecation warnings by replacing the feature with another that has a similar syntax (e.g. auto_ptr -> unique_ptr and let the compiler find out where you should move instead of copy). I learned a lot about regular expressions during such a large scale replacement mission. Sometimes though it’s not that easy and you have to decide whether you do the replacement slowly one by one or just silence the warning and take the risk that one day the compiler will drop support for that feature completely.

      Reply

  4. When developing, I go one step further and enable remarks (IAR compiler feature) when compiling in debug mode. These are less severe than warnings so they aren’t critical, but it’s something that I feel should be looked at because it may indicate a lapse in our high standards of coding. Once our code is remark-free, it’s ready for static analysis and testing.

    Reply

  5. warning: you used the word “adapt” where “adopt” would be more appropriate. In an too!

    Reply

    1. Thanks, fixed “adopt”. I don’t understand “in an too” though. Could you elaborate?

      Reply

  6. Yep it is most important to resolve all warnings.
    I have a special method to resolve some of them, convert your code to a cross platform console application over several operation systems and several compiler versions an IDEs.

    most warnings will raise different messages with different compilers/versions so you will be able to consolidate your code.

    with optimization (OpenMP) for example some uninitialized parameters warnings can be severely dangerous, it is most likely
    the results of Imaging 2D algorithms will give non bit exact results (sanity tests) between different executions/computers etc’…
    it can be caused when one task/thread read a parameter before an other is setting its initial value under some condition or loop in an other thread context.

    usage of multiple definition macros can give different results with different compilers.

    even build scripts and macros can reveal unexpected linkage of wrong headers/static libraries/shared libraries that raise a warning.

    one most strange error I encountered once – an invisible character
    in some string (Ubuntu nautilus “copy file” can pass a file path to the clipboard with an invisible character at its end and create a different file name that the program will not find).

    good blogging.
    Ori

    Reply

  7. This reminds me of the language ELM where the compiler was written, so it will display useful output even on errors:
    http://elm-lang.org/blog/compilers-as-assistants

    For me it took long for example to understand what the compiler wants to tell me if it says something about an “assignment to rvalue” instead of just saying “No, you can’t assign a value to , because it is only allowed on the right side of an assignment operator”.
    Yes, this is longer but much more easier to understand.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *