Thursday, November 5, 2009

Byte Order Conversion in Qt

For my recent re-writing of Presence to use the Qt library, I needed to be able to do byte order swapping on two and four byte integers (short and int). This I used when serializing/marshalling/packing stuff up before transmitting them over the wire. I know that the "right" way of doing that in Qt would be to use QDataStream, which will then handle stuff like byte order conversion, but I needed to be able to pack my own data, so that a QDataStream-capable reader was not required on the other side of the socket connection.

Byte order conversion is done using the four functions (macros really) called htons, ntohs, htonl, and ntohl that may be found in inet/arpa.h on any Unix system. So of course I included that file and went happily on with my coding. But... when I tried to compile my new version of Presence under Windows I realized that inet/arpa.h does not exist on Windows. It probably resides in winsock.h I guess, but I _really_ do not want to have platform specific code in my project, so I decided to implement them myself instead :-)

Using Qt you can ask for your systems endianness by using the QSysInfo class, so a portable implementation of the needed functions is easy to do:
#define BYTE_SWAP4(x) \
(((x & 0xFF000000) >> 24) | \
((x & 0x00FF0000) >> 8) | \
((x & 0x0000FF00) << 8) | \
((x & 0x000000FF) << 24))

#define BYTE_SWAP2(x) \
(((x & 0xFF00) >> 8) | \
((x & 0x00FF) << 8))

quint16 _htons(quint16 x) {
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
return x;
}
else {
return BYTE_SWAP2(x);
}
}

quint16 _ntohs(quint16 x) {
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
return x;
}
else {
return BYTE_SWAP2(x);
}
}

quint32 _htonl(quint32 x) {
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
return x;
}
else {
return BYTE_SWAP4(x);
}
}

quint32 _ntohl(quint32 x) {
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
return x;
}
else {
return BYTE_SWAP4(x);
}
}


Note that the functions have a '_' prepended - otherwise some compilers may get confused.

Using these functions I do not need to have any platform specific code in my project. This comes at the cost of actually doing a function call when byte order conversion is needed, as opposed to simply using a macro. So if your code is very performance critical you should not use this code - but then again, if your code is that performance critical you should probably not be using C++ ;-)

1 comment:

  1. I know this is old af but you literally saved me hours of shit with qt networking. Thanks!

    ReplyDelete