'How to unpack 32bit integer packed in a QByteArray?
I'm working with serial communication, and I receive 32bit integers in a QByteArray, packed in 4 separate bytes (little-endian).
I attempt to unpack the value from the 4 bytes using QByteArray::toLong() but it fails the conversion and returns the wrong number:
quint8 packed_bytes[] { 0x12, 0x34, 0x56, 0x78 };
QByteArray packed_array { QByteArray(reinterpret_cast<char*>(packed_bytes),
sizeof(packed_bytes)) };
bool isConversionOK;
qint64 unpacked_value { packed_array.toLong(&isConversionOK) };
// At this point:
// unpacked_value == 0
// isConversionOK == false
The expected unpacked_value is 0x78563412 (little-endian unpacking). Why is the conversion failing?
Solution 1:[1]
toLong() converts a char * digits string to long. Not bytes. And your values likely don't make the up the string "0x78563412" or its decimal equivalent. Hence the 0 result.
If you need the byte values interpreted as long you can do something like:
long value;
value == *((long*)packed_bytes.data());
Or to access an array of bytes as long array:
long * values;
values == (long*)packed_bytes.data();
values[0]; // contains first long
values[1]; // contains second long
...
Don't know whether my examples work out of the box but it should make clear the principle.
Check out this example:
char bytes[] = {255, 0};
QByteArray b(bytes, 2);
QByteArray c("255");
qDebug() << b.toShort() << c.toShort();
qDebug() << *((short*)b.data()) << *((short*)c.data());
the output is:
0 255
255 13618
You may need to change the byte order depending on the endianess. But it does what you need.
Solution 2:[2]
you can build your qint64 with bit manipulators:
#include <QtGlobal>
#include <QByteArray>
#include <QDebug>
int main()
{
quint8 packed_bytes[] { 0x12, 0x34, 0x56, 0x78 };
QByteArray packed_array { QByteArray(reinterpret_cast<char*>(packed_bytes),
sizeof(packed_bytes)) };
qint64 unpacked_value = 0;
unpacked_value |= packed_array.at(0) |
packed_array.at(1) << 8 |
packed_array.at(2) << 16 |
packed_array.at(3) << 24;
qDebug() << QString("0x%1").arg(unpacked_value, 0, 16);
}
Solution 3:[3]
Here's a generic solution for converting a QByteArray to "some other type" (such as what is specifically asked in the question) by running it through a QDataStream (as done by the accepted answer).
DISCLAIMER: I am only advocating for using this in a private implementation. I am aware there are many ways one could abuse the macro!
Using this macro, you can easily produce many conversion functions such as the examples I've provided. Defining a series of such functions in this way may be useful if you need to pull a variety of types out of a stream. Obviously, you could tweak the macro for your use case, the point is the pattern can remain basically same and be put in a macro like this.
#define byteArrayToType( data, order, type ) \
QDataStream stream( data ); \
stream.setByteOrder( order ); \
type t; \
stream >> t; \
return t;
Example functions, which simply wrap the macro:
16 bit, signed
qint16 toQInt16( const QByteArray &data,
const QDataStream::ByteOrder order=QDataStream::BigEndian )
{ byteArrayToType( data, order, qint16 ) }
32 bit, signed
qint32 toQInt32( const QByteArray &data,
const QDataStream::ByteOrder order=QDataStream::BigEndian )
{ byteArrayToType( data, order, qint32 ) }
64 bit, signed
qint64 toQInt64( const QByteArray &data,
const QDataStream::ByteOrder order=QDataStream::BigEndian )
{ byteArrayToType( data, order, qint64 ) }
Solution 4:[4]
Cast the Byte array to the required format and use the built-in function qFromBigEndian or qFromLittleEndian to set the Byte order. Example code is shown below,
QByteArray byteArray("\x45\x09\x03\x00");
quint32 myValue = qFromBigEndian<quint32>(byteArray);
qDebug() << "Hex value: " << QString("0x%1").arg(myValue, 8, 16, QLatin1Char( '0' ));
myValue holds the converted value.
Don't forget to include the header file <QtEndian>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Paraboloid87 |
| Solution 3 | |
| Solution 4 | Vinu Raja Kumar C |
