2

Using Qt5.4, I build the function generateRandomIDOver2Bytes. It generates a random number and it puts it onto a variable that occupies exactly two bytes.

QByteArray generateRandomIDOver2Bytes() {
    QString randomValue = QString::number(qrand() % 65535);
    QByteArray x;
    x.setRawData(randomValue.toLocal8Bit().constData(), 2);
    return x;
}

My issue is reverting the so generated value in order to obtain, again, an integer. The following minimum example actually does not work:

QByteArray tmp = generateRandomIDOver2Bytes(); //for example, the value 27458 
int value = tmp.toUInt(); 
qDebug() << value; //it prints always 9

Any idea?

3
  • Are you aware that randomValue contains the random number in ASCII characters for the decimal digits? That's what QString::number() returns. Obviously, for the range of [0, 65535], this will occupy upto 5 bytes. If you want to store [0, 65535] in two bytes, conversion to string (text) is a bad choice. A short (or std::uint16_t) (storing it as binary integer) would be much more sufficient, wouldn't it? Then you could read the two bytes of the short and store them into the QByteArray. (Or, did I misunderstand your intention completely?) Commented Jan 8, 2020 at 8:41
  • You are perfectly right. In fact, my problem can be resume in two points: 1- How to convert a std::uint16_t in a QByteArray that occupies exactly two bytes? and 2- How to revert the QByteArray and re-obtain the short? Commented Jan 8, 2020 at 8:47
  • Thank you for your effort Scheff. I saw the answer of p-a-o-l-o and I am trying to reproduce it. Commented Jan 8, 2020 at 9:22

2 Answers 2

3

A 16 bit integer can be split into individual bytes by bit operations.

This way, it can be stored into a QByteArray.

From Qt doc. of QByteArray:

QByteArray can be used to store both raw bytes (including '\0's) and traditional 8-bit '\0'-terminated strings.

For recovering, bit operations can be used as well.

The contents of the QByteArray does not necessarily result into printable characters but that may not (or should not) be required in this case.

testQByteArrayWithUShort.cc:

#include <QtCore>

int main()
{
  quint16 r = 65534;//qrand() % 65535;
  qDebug() << "r:" << r;
  // storing r in QByteArray (little endian)
  QByteArray qBytes(2, 0); // reserve space for two bytes explicitly
  qBytes[0] = (uchar)r;
  qBytes[1] = (uchar)(r >> 8);
  qDebug() << "qBytes:" << qBytes;
  // recovering r
  quint16 rr = qBytes[0] | qBytes[1] << 8;
  qDebug() << "rr:" << rr;
}

Output:

r: 65534
qBytes: "\xFE\xFF"
rr: 65534
Sign up to request clarification or add additional context in comments.

Comments

1

Given the random value 27458, when you do this:

x.setRawData(randomValue.toLocal8Bit().constData(), 2);

you're filling the array with the first two bytes of this string: "27458".

And here:

int value = tmp.toUInt();

the byte array is implicitly cast to a string ("27"), which in turn is converted to a numeric value (an unsigned integer).

Let's try something different, that maybe suits your need.

First, store the value in a numeric variable, possibly of the deisred size (16 bits, 2 bytes):

ushort randomValue = qrand() % 65535;

then just return a byte array, built using a pointer to the ushort, cast to char * (don't use setRawData, because it doesn't copy the bytes you pass it in, as well explained here):

return QByteArray(reinterpret_cast<char *>(&randomValue), 2);

To get back to the value:

QByteArray tmp = generateRandomIDOver2Bytes(); //for example, the value 27458

ushort value;
memcpy(&value, tmp.data(), 2);

Please notice: types do matter here. You wrote an uint in a byte array, you must read an uint out of it.

All this can be generalized in a class like:

template <typename T>
class Value
{
    QByteArray bytes;
public:
    Value(T t) : bytes(reinterpret_cast<char*>(&t), sizeof(T)) {}
    T read() const
    {
        T t;
        memcpy(&t, bytes.data(), sizeof(T));
        return t;
    }
};

so you can have a generic function like:

template<typename T>
Value<T> generateRandomIDOverNBytes()
{
    T value = qrand() % 65535;
    qDebug() << value;
    return Value<T>(value);
}

and safely use the type your prefer to store the random value:

Value<ushort> value16 = generateRandomIDOverNBytes<ushort>();
qDebug() << value16.read();

Value<int> value32 = generateRandomIDOverNBytes<int>();
qDebug() << value32.read();

Value<long long> value64 = generateRandomIDOverNBytes<long long>();
qDebug() << value64.read();

5 Comments

Thank you p-a-o-l-o. You highlighted some of my weaknesses, but I did learn a lot. I am trying to reproduce it, I let you know soon.
Dear p-a-o-l-o, the majority seems ok. Unfortunately, printing "value" after: ushort value; memcpy(&value, tmp.data(), 2); Always returns 0. I cannot get why.
Yes, I well returned an return QByteArray(x); . I still have the issue. However, the solution of Scheff seem to work in my case.
@JoeMatt I edited the answer again: just return a QByteArray and don't use setRawData at all.
Thanks p-a-o-l-o! I will reproduce it soon.

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.