Why Compiler Warnings are Your Friends


By Alex Allain
Compilers emit both erorrs, which prevent your code from compiling at all, and warnings, which indicate a potential problem, but still let your code compile. (Unless you have ask the compiler to treat warnings as errors, such as with the -Werror flag to gcc). Most programmers consider it important to fix all compiler warnings - while they are often benign, some compiler warnings will alert you to real, potentially hard to find, bugs in your code. Let's take a look at how they help!

Catch Bugs Before Testing

Compiler warnings often indicate future bugs that you would otherwise see only at runtime. For instance, the warning "assignment in conditional" might mean that you've written
if ( x = 5 )   //uh oh, x = 5 will evaluate to the value 5, which is always true
{
        /* ... */
}
when what you really meant was
if ( x == 5 )
{
        /* ... */
}


Just for fun, here's an even more compelling example of when you'd have trouble finding the bug during testing.
if ( x = 0 )
{
        std::cout << "x is zero!";
}
Since x would generally not equal zero, the if statement generally wouldn't be expected to execute. Now, since x = 0 evaluates to false, this statement will always be false. If you never test the situation where x actually is 0, then you won't notice that the body of the if statement never executes.

Catch Bugs that are Hard to Find in Testing

Compiler warnings often surface issues that might be difficult to find during testing. For example, your compiler can warn you that you are reading the value of an uninitialized variable; this can be hard to find in testing because the value of the variable will be different every time the program runs - so sometimes it might still work!

Another insidious bug is forgetting to return a value from a function. Sometimes this can be tricky to spot even once your compiler points it out. This might happen when your function has multiple paths through the code and most of them return a value; it's left up to you to find the one that doesn't.
int searchArray(int to_search[], int len, int to_find)
{
        int i;
        for( i = 0; i < len; ++i )
        {       
                if ( to_search[i] == to_find )
                {
                        return i;
                }
        }
}
Notice that most of the time, this function will return a value. It's only when the value isn't in the array that it doesn't. This bug can be hard to spot in later testing both because this may be an uncommon occurrence and because the results of not returning a value when one is expected can be extremely weird. For instance, you might get a valid index of the array, or you might get a value that is either way to big or way too small. In either case, the problems in the running program wouldn't appear within the function at all but afterward, when the return value is used.

Lessons to Take Away

While you've picked up a few tips for combating compiler warnings, the real message is the mindset you should have--catch bugs as early as possible, and take advantage of your tools, like the compiler, that tell you exactly where problems are before you discover something mysterious during testing. Sometimes there may be no need for you to set your compiler to fail on any warnings, but if you use automated scripts for building your program or tend to ignore the compiler unless it fails, then this might be a useful thing to do. You'll have to look at your compiler documentation for exactly how to set this up; on gcc and g++, all you need to use is the -Werror flag ("treat warnings as errors").

Furthermore, if you don't understand what a compiler warning means, it's probably best to trust that the compiler is telling you something valuable. I've had experiences where I was convinced that my code was correct and wasn't entirely sure what the compiler could be complaining about. But after investigating my compiler's complaints, I realized I had made a subtle mistake in a boolean expression that would have been nearly impossible to hone in on when debugging--it was much easier to catch the mistake while the code was fresh in my mind code rather than hours or possibly days later when I might (with luck) have found the bug due to the mistake.
Related articles

Tips and tricks from combating compiler and linker errors

Read more about the compiling and linking process