How to Make SafeInt Compatible with Windows Platform SDK Headers

Invasive preprocessor macro definitions strike again.

Last time, I introduced the convenient and easy-to-use SafeInt C++ library.

You might have experimented with it in a simple C++ console application, and noted that everything is fine.

Now, suppose that you want to use SafeInt in some Windows C++ project that directly or indirectly requires the <Windows.h> header.

Well, if you take your previous C++ code that used SafeInt and successfully compiled, and add an #include <Windows.h>, then try to compile it again, you’ll get lots of error messages!

Typically, you would get lots of errors like this:

Error C2589 ‘(‘: illegal token on right side of ‘::’

Error list in Visual Studio, when trying to compile C++ code that uses SafeInt and includes Windows.h.
Error list in Visual Studio, when trying to compile C++ code that uses SafeInt and includes <Windows.h>

If you try and click on one of these errors, Visual Studio will point to the offending line in the “SafeInt.hpp” header, as shown below.

An example of offending line in SafeInt.hpp.
An example of offending line in SafeInt.hpp

In the above example, the error points to this line of code:

if (t != std::numeric_limits<T>::min() )

So, what’s going on here?

Well, the problem is that the Windows Platform SDK defines a couple of preprocessor macros named min and max. These definitions were imported with the inclusion of <Windows.h>.

So, here the C++ compiler is in “crisis mode”, as the above Windows-specific preprocessor macro definitions conflict with the std::numeric_limits::min and max member function calls.

So, how can you fix that?

Well, one option could be to #define the NOMINMAX preprocessor macro before including <Windows.h>:

#define NOMINMAX
#include <Windows.h>

In this way, when <Windows.h> is included, some preprocessor conditional compilation will detect that NOMINMAX is defined, and will skip the definitions of the min and max preprocessor macros. So, the SafeInt code will compile fine.

Preprocessor logic in a Windows SDK header (minwindef.h) for the conditional compilation of the min and max macros.
Preprocessor logic in a Windows SDK header (<minwindef.h>) for the conditional compilation of the min and max macros

So, everything’s fine now, right?

Well, unfortunately not! In fact, if you may happen to include (directly or indirectly) the GDI+ header <gdiplus.h>, you’ll see that you’ll get compilation errors again, this time because some code in GDI+ does require the above Windows definitions of the min and max macros!

So, the previous (pseudo-)fix of #defining NOMINMAX, caused another problem!

Well, if you are working on your own C++ code, you can make your code immune to the above Windows min/max preprocessor macro problem, using an extra pair of parentheses around the std::numeric_limits<T>::min and max member function calls. This additional pair of parentheses will prevent the expansion of the min and max macros.

// Prevent macro expansion with an additional pair of parentheses
// around the std::numeric_limit's min and max member function calls.
(std::numeric_limits<T>::min)()
(std::numeric_limits<T>::max)()

However, that is not the case for the code in SafeInt.hpp. To try to make SafeInt.hpp more compatible with C++ code that requires the Windows Platform SDK, I modified the library’s code with the extra pairs of parentheses (added in many places!), and submitted a pull request. I hope the SafeInt library will be fixed ASAP.

Leave a comment