I maintain an open-source library that is supposed to run on multiple platforms and offers (among other) mathematical routines on native data types. We want to offer 64 bit calculations wherever possible.
Our target platforms are Linux and OSX on 32 bit and 64 bit, Windows is not supported yet but most of the code is known to run under Windows and thus we'd keep the possibility to easily port to Windows in the not-so-distant future. Hence, as for http://en.cppreference.com/w/cpp/language/types, we are interested in ILP32, LLP64 and LP64.
We also interact with gmp (which only offers constructors for int
and long
, but not long long
.)
We now ran into problems that boiled down to which native integer types we use as a default for our number type:
- If we use
int
, we fall back to 32 bits on 64 bit platforms. - If we use
long
, we have inconsistent behavior between Linux/OSX 64 vs. Windows 64: Windows will fail to employ 64 bit calculations. - If we use
long long
, using gmp becomes a mess because creatingmpz_class
from along long
results in an ambiguous overload. We'd have to cast the numbers beforehand back to long (and thus effectively using only 32 bits on Windows in a number of places.) - If we use
std::int64_t
and alike, the typedefs differ between platforms and thus we get the same problems, just different ones for each platform...
Is there some kind of best practice for that? Is it even possible to avoid these problems or are they inherent to the C++ type system?
Of course, the problems don't end here. Further open questions to be considered:
- How do each of these solutions interact with for example
std::size_t
?std::size_t
has it's purpose, but sometimes it needs to interact with the numbers we calculate on. Obviously, we don't want to cast back and forth all the time. - How do we handle usage with other number types? If we offer a function
f(T)
and provide overloads forT = int,long,long long
but the user uses it withstd::int64_t
, can we avoid inconsistent behavior between different platforms? (that have differing definitions ofstd::int64_t
) If we also provide overloads forstd::int64_t
, we'll have duplicate overloads.
PS: I already read c-long-long-int-vs-long-int-vs-int64-t and should-i-use-long-long-or-int64-t-for-portable-code. I got some insight there what exactly happens and why it is like this, but could not derive a solution...