7

I'm trying to find a Qt function that can convert bytes to int with the same endianness that I'm using below. I feel like I'm definitely reinventing the wheel here, and that there must be something in the Qt libs to do this already. Does it exist?

// TODO: qt must have a built in way of converting bytes to int.
int IpcReader::bytesToInt(const char *buffer, int size)
{
    if (size == 2) {
        return
            (((unsigned char)buffer[0]) << 8) +
              (unsigned char)buffer[1];
    }
    else if (size == 4) {
        return
            (((unsigned char)buffer[0]) << 24) +
            (((unsigned char)buffer[1]) << 16) +
            (((unsigned char)buffer[2]) << 8) +
              (unsigned char)buffer[3];
    }
    else {
        // TODO: other sizes, if needed.
        return 0;
    }
}

// TODO: qt must have a built in way of converting int to bytes.
void IpcClient::intToBytes(int value, char *buffer, int size)
{
    if (size == 2) {
        buffer[0] = (value >> 8) & 0xff;
        buffer[1] = value & 0xff;
    }
    else {
        // TODO: other sizes, if needed.
    }
}

Edit: The data is always big endian (no matter what OS), so for example 101 would be [0, 0, 0, 101] and 78000 is [0, 1, 48, 176].

5
  • What's wrong with good ol' std::memcpy? Commented Jul 6, 2012 at 22:23
  • I'm not sure, will it read and write in the same format as my functions? This is for an existing network protocol that I can't alter. Commented Jul 6, 2012 at 22:27
  • That depends on the endianness of the system running this code; if it's backwards, that's what ntohl and ntohs are for. Commented Jul 6, 2012 at 22:29
  • Ah, ok, a code sample would be great :-) the code is cross platform so the endianness is undefined (but as it happens I'm on little endian Windows right now) -- but the protocol is big endian. Commented Jul 7, 2012 at 10:15
  • Was a solution ever found for this question? Commented Dec 20, 2013 at 19:46

3 Answers 3

3

The following functions seems to fit your needs :

From : #include <QtEndian>

Sign up to request clarification or add additional context in comments.

1 Comment

It should be noted, internally these use memcpy.
1

Your code is pretty simple and easy to follow but you could use Qt's QByteArray like so (note: I didn't try compiling this):

int IpcReader::bytesToInt(const char *buffer, int size)
{
  QByteArray b(buffer, size);
  return b.toInt();
}

void IpcClient::intToBytes(int value, char *buffer, int size)
{
  QByteArray b = QByteArray::number(value);
  strncpy(buffer, (const char*)b, size);
}

Note that the endianness is going to be the same as the machine it is run on.

3 Comments

Yeah I think the endianness is the problem, the protocol has it the other way round to my machine which is why this didn't work for me; the bytesToInt function would always return 0 which is why I didn't do it that way in the first place.
The protocol is big endian by the way.
Most network protocols are Big Endian, or Network Byte Order. Simply call the ntohs/ntohl and htons/htonl functions to swap between local byte order (probably little endian) and network byte order (big endian). ntohs/ntohl convert from your local byte order (little or big endian) to network byte order (big endian). htons/htonl convert from network byte order (big endian) to your local byte order (little or big endian). These functions know what your local byte order is so you don't have to do anything special.
1

Wouldn't be a QByteArray with a QDataStream sufficient?

int IpcReader::bytesToInt(const char *buffer, int size)
{
    QByteArray byteArr(buffer,size);
    QDataStream ds(&byteArr,QIODevice::ReadOnly);

    if(little_endian_usage) // little endian check or something similar here
         ds.setByteOrder(QDataStream::LittleEndian);
    else
         ds.setByteOrder(QDataStream::BigEndian);

    int ret;
    if(size == 2){
        qint16 tmp;
        ds >> tmp;
        ret = tmp;
    } else if(size == 4){
        qint32 tmp;
        ds >> tmp;
        ret = tmp;
    } else if(size == 1){
        qint8 tmp;
        ds >> tmp;
        ret = tmp;
    }
    return ret;
}

If you don't want to create a copy of your buffered data you can use QByteArray byteArr =QByteArray::fromRawData(buffer, size). You can also use a QDataStream to write an int back into a QByteArray or a raw buffer (use QByteArray::fromRawData() for the latter).

4 Comments

Thanks but same behaviour as syplex's code -- the endianness is the same as the system which is opposite to the protocol. So if I use your code it always returns 0 for the protocol.
@nbolton: Use QDataStream::setByteOrder in this case.
Hmm, odd... I've tried ds.setByteOrder(QDataStream::BigEndian) but the code still returns 0. I've tried playing around with QByteArray before and got the same results. My code works perfectly with the protocol which is big endian for sure (see the edit on my question).
Then just stick to ildjarn's suggestion: use memcpy and ntohl/ntohs, which will convert a big endian long/short from network order (big endian) to host order (depends on your system). memcpy is defined in <cstring>, ntoh* in <netinet/in.h> (*nix) or <winsock2.h> (win)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.