Author: Chloé Lourseyre
While working on not-so-old code, I ended up with a strange compilation error in MS Visual Studio :
Here was the incriminated code :
//... const T_LongType BIG_OFFSET = std::numeric_limits<T_LongType>::max() / 2; //...
And here the errors :
1>MyFile.cpp(42): error C2589: '(' : illegal token on the right side of '::' 1>MyFile.cpp(42): error C2059: syntax error : '::' 1>MyFile.cpp(42): error C2059: syntax error : ')' 1>MyFile.cpp(42): error C2059: syntax error : ')'
It came with a bunch of warnings I won’t even bother writing here.
I took me a hella lot of time to find out what was wrong. The type
T_LongType was correctly defined (actually a typedef of
long) and I didn’t forget to include
Many of you may already know the culprit, and it’s the following line :
Indeed, if we look into the code of this library, we can see a surprising piece of code :
#ifndef NOMINMAX #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif /* NOMINMAX */
To my defense, the file in which the error occured did not include
windows.h. It was included by another header.
The fact that
windows.h defines macros called
max implies that, during the preprocessor phase of the compilation, every instances of the words
max will be replaced.
This means that, after the preprocessing, instead of seeing this :
const T_LongType BIG_OFFSET = std::numeric_limits<T_LongType>::max() / 2;
The compiler will see this :
const T_LongType BIG_OFFSET = std::numeric_limits<T_LongType>::(((a) > (b)) ? (a) : (b))() / 2;
Which makes no sense, thus the compilation errors mentioned above.
Many reasons to not include windows.h
Here is a non-exhaustive list that why it is a bad practice to include this header :
- It breaks the standard library just by including it. The way we use the functionality of the standard library should work whatever the header files we include.
- It forces you to define
NOMINMAXand the beginning of each headers that include
windows.h. And if you ever happen to forget this, every file that will include your header will have to define it.
- Since it’s OS-dependant, it’s better to avoid it as long as you can. If you use where you don’t need to, you won’t be able to port your code to other systems, you may obtain bad coding habits (by relying too much on it) and to not forget that the more specific a library is, the less maintained it will be.
All in all there are ways to use
windows.h safely, but you must be absolutely be solid in how you include it to avoid side-effects to other sources and headers.
As long as you can, don’t use it.
Author: Chloé Lourseyre