Today I'm gonna tell you about a trap I've been falling into once a two years or something, and I believe many other C/C++ programmers have.
This will be about XXX_MIN and XXX_MAX macros from <limits.h>. As it clearly stands from their names, these macros are a minimum and a maximum numerical values which can be stored in a variable of some numerical type. That is, INT_MAX is a maximum value representable by a variable of type of int, and is precisely equal to 2^31–1 on most 32-bit systems; and INT_MIN equals –(2^31–1), or –INT_MAX. For unsigned types, XXX_MAX equals to 2^bits_per_type–1 and XXX_MIN is expected to be zero.
This is all good, and using these macros is strictly advised for writing fine cross-platform code, but, believe me, you'll find yourself in trouble as soon as you're using it with floating point types, because FLT_MIN, DBL_MIN and LDBL_MIN really ruin your party. For some diabolic reason they don't stand for what their integral type counterparts do; in fact these are a representation of the least positive number that can be encoded with the type. That's right, FLT_MIN is actually 1/FLT_MAX, DBL_MIN is 1/DBL_MAX, and so on.
The things turn even worse when you're in the C++ boat and using std::numeric_limits<>. This generic behaves badly, too, and on my opinion compromises the very idea of being a template.
#include <iostream> #include <limits> template <typename T> std::string check() { T def = T(), // initialized with 0 min = std::numeric_limits<T>::min(), max = std::numeric_limits<T>::max(); return min < def && def < max ? "true" : "false"; } int main() { std::cout << "int: " << check<int>() << ", double: " << check<double>() << std::endl; return 0; }
It for sure outputs
int: true, double: false
What can I say? Thank you Kernighan, and thank you Ritchie! See you in hell guys, for the biggest evil on Earth being an inconsistent design.