I am working with Qt in a cross-platform environment. And we are running into the following problem: On Windows, both int
and long int
are 32-bit integers; on 64-bit MacOS and Linux, int
is 32-bit and long int
is 64 bit (see https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models).
So, cross-platform libraries tend to provide their own fixed-bit typedefs. On Windows, Qt defines quint32
to be a unsigned int
and does not use unsigned long
integers. Another library defines its Uint32
however to be unsigned long
. So, both are in fact 32-bit unsigned integers but have a different primitive data-type.
Now, it happens, that we try to use QDataStream
serialization which is defined for quint32
with Uint32
data and to our surprise (or not), Visual C++ complains about the QDataStream
operators not being defined for unsigned long
which is true because Qt uses the almost equivalent unsigned int
instead.
OK, the workaround is to provide
#ifdef Q_OS_WIN
inline QDataStream & operator >> (QDataStream & stream, Uint32 & value)
{ return stream >> reinterpret_cast<quint32 &>(value); }
inline QDataStream & operator << (QDataStream & stream, Uint32 value)
{ return stream << quint32(value); }
#endif // def Q_OS_WIN
My question is: Why do I need to reinterpret_cast
? I would feel way more comfortable with a static_cast
given that to my understanding the data-types are in fact the same. Here be dragons?
int
and long
are different data types, even if they happen to have the same properties otherwise.
Your operator>>
causes undefined behaviour due to strict aliasing violation; the correct way to write the code would be:
inline QDataStream & operator >> (QDataStream & stream, Uint32 & value)
{
quint32_t v;
stream >> v;
value = v;
return stream;
}
(Note: I'm assuming the QDataStream>> has the same property as C++11 istream>> in that it sets value to 0
on read failure; if not then you'll need to include a branch so that value = v;
is not executed if read failed).
You can use static_cast
for the operator<<
since it is a value transformation. In fact you should be able to omit that operator<<
entirely.
The problems you are lamenting in your question are a corollary of projects making up their own typedefs instead of using the standardized ones. Unfortunately it is just something you have to deal with until such time as the projects decide to move to standardized types. If both had used uint32_t
then this problem wouldn't exist.