Just say No to Microsoft C warning level 4

09/23/2012

 

While recent Microsoft C compilers have reasonable warning capability, the commonly used predefined setting of W4 often results in permanent damage to a project's code. The best solution is to avoid predefined hard-coded warning levels. Instead, build your own custom warning level by enabling warnings individually. This allows enabling useful warnings that are not enabled by level 4, effectively resulting in your own 'warning level 5'. Importantly, warnings that are not compatible with your project or coding habits can be disabled.

 

One warning enabled by Microsoft warning level 4 that is especially troubling is one that flags the ordinary integer truncation that occurs when assigning a longer integer type to a shorter integer type. For example:

 

UINT8 foo (UINT32 a)
   {
   return a;
   }

 

warning C4244: 'return' : conversion from 'UINT32' to 'UINT8', possible loss of data

 

If a simple project is carefully coded from scratch with this warning enabled, it is sometimes possible to avoid any damaging side effects. But most projects are not coded this way. For example, someone decides to use Microsoft warning level 4 long after structure definitions and function prototypes have been frozen. The end result is something like this:

 

UINT8 foo (UINT32 a)
   {
   return (UINT8) a;
   }

 

There are problems with this solution:

 

1) The integer truncation remains. The type cast simply turns off the warning.

2) Implicit type conversion is permanently replaced by a hard-coded type conversion.

 

The effects of this commonly used hard-coded type cast solution to warning C4244 are all negative. First of all, the code is still not warning level 4 compliant. You have simply turned off the warning for this statement. A more serious and unintended effect is that implicit type conversion is now disabled. In the original code, the compiler chooses the conversion that preserves the most data. For example, if the function return value is changed from 8 bits to 16 bits, the compiler will automatically increase the size of the conversion from 8 bits to 16 bits. But once the type cast is added, the compiler is forced to truncate the return value to 8 bits.

 

What is the biggest danger of using the hard-coded type cast solution to warning C4244? It is the case where the size of the converted data is increased by a prototype or structure change. The hard-coded type cast prevents the compiler implicit conversion mechanism from automatically choosing a suitable cast. In some cases the resulting data loss problem can be difficult to debug because the hard-coded type cast may have been applied in dozens of places in the source code.

 

With the original code, the data size can be expanded by changing a single prototype or structure definition. But after warning level 4 forces the use of type casts to suppress every occurrence of warning C4244, this is no longer true. Now, a data expansion that previously took a single code change requires dozens of sometimes difficult to identify code changes.

 

A sad reality is that the code damage resulting from use of warning level 4 is often irreversible. This is because a large project accumulates thousands of these undesirable hard-coded type casts. To remove the type casts, or to redesign the project to be warning level 4 compatible, is impractical.

 

This problem is unique to the Microsoft C compiler, and affects less experienced users of the language. While a more advanced C compiler such as gcc has the capability to warn about implicit conversion to a smaller type (-Wconversion), it is not enabled by any predefined warning setting such as -Wall or -Wextra.