Warning: Don’t Ignore Warnings!

How many times have you run across code that looks fine, works fine, but still generates a message like “Signed/unsigned mismatch” when we compile it? How many times have you thought to yourself, “that’s stupid, I know this code is fine.” and continued working? I think if you were to poll 100 programmers (and they were honest), all 100 would say they’ve done that at least once in their life.

Let’s look at a more concrete example of what I’m talking about. Try compiling the following code in Visual Studio, and you will see a warning.

std::string str = "This is a string";
for (int i = 0; i < str.length(); ++i) {  // warning C4018: '<' : signed/unsigned mismatch

}

As programmers, we read that code and can understand it will never pose a problem. The length of the string is a fixed size, it’s quite small, so we never have to worry about the length of the string becoming negative. So why does the compiler complain?

While compilers may seem magical to some, it’s better to think of them as dumb translation devices. They translate source code into machine code (going through several stages first). When you get a syntax error, it means that there’s something syntactically amiss with your source code — it doesn’t match the parser’s grammar, and so the compiler tells you “this is flat-out wrong.” You can also get semantic errors, where the syntax is fine but the semantics do not meet the requirements of the language (for instance, trying to call an instance method that doesn’t exist on an object). Again, the compiler will tell you “this is wrong” and not continue. But warnings are special. Warnings are the compiler’s attempts at mind reading. When you get a warning from the compiler, it means that the syntax is correct, and the semantics are mostly correct, but there’s some ambiguity remaining. When the compiler spits out a warning, it is basically saying “I don’t know for sure what you meant, so I just picked a behavior on your behalf.” In essence, a warning is the compiler’s mechanism for telling you that it doesn’t really know what you want it to do.

From our example above, there are two possible outcomes the programmer could want. The variable “i” could be converted from signed int to string::size_type for the < comparison, or the rvalue from calling string::size could be converted from string::size_type to signed int. There could be an argument for either conversion, and the compiler simply has to pick one. In this case, whatever one the compiler picks will not cause a problem. But that's this case. The problem with warnings is that they tend to multiply. You ignored one line item that says "signed/unsigned mismatch", so your brain instinctively stops caring about other line items with the same text. After all, who remembers whether the acceptable case was on line 81 or on line 124. But just because one warning is acceptable doesn't mean they all will be. For example: [cpp] int GetStoppingPoint(); // Defined elsewhere std::string str = "This is a string"; for (std::string::size_type i = str.length(); i >= GetStoppingPoint(); --i) { // warning C4018: '>=' : signed/unsigned mismatch } [/cpp] Here again we see a signed/unsigned mismatch. But what happens if GetStoppingPoint returns 0? Performing --i when i == 0 will wrap i around to the largest positive value allowed by string::size_type. That means i will always be greater than or equal to zero, and you've got an infinite loop. This is a case where there's a definite error in your code. Resist the urge to ignore warnings in your code. You may be able to logically reason that a particular warning can be ignored for one line of code, but then you run the very real risk of masking true errors in your code when you start to get multiple warnings. When the compiler generates an error, it is telling you "there is a 100% chance this code is wrong." You are not allowed to ignore this. When the compiler generates a warning, it is telling you "there is a good chance this code is wrong." While you are allowed to ignore it, you should listen to your compiler, and fix those warnings! The best attitude to take is: warnings are still errors (and most modern compilers allow you to treat them as such). tl;dr: ignore warnings at your own peril.

This entry was posted in C/C++ and tagged , , . Bookmark the permalink.

Leave a Reply

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