如何解压 QByteArray 中的 32 位整数?
How to unpack 32bit integer packed in a QByteArray?
我正在使用串行通信,我在 QByteArray
中接收到 32 位整数,这些整数被打包成 4 个单独的字节(小端)。
我尝试使用 QByteArray::toLong()
从 4 个字节中解压值,但转换失败并且 returns 错误的数字:
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
预期的 unpacked_value
是 0x78563412(小端解包)。为什么转换失败?
toLong()
将 char * digits string
转换为 long。不是字节。并且您的值可能不会构成字符串“0x78563412”或其等效的十进制值。因此结果为 0。
如果您需要解释字节值,只要您可以执行以下操作:
long value;
value == *((long*)packed_bytes.data());
或者访问一个字节数组作为长数组:
long * values;
values == (long*)packed_bytes.data();
values[0]; // contains first long
values[1]; // contains second long
...
不知道我的例子是否开箱即用,但应该说清楚了原理。
看看这个例子:
char bytes[] = {255, 0};
QByteArray b(bytes, 2);
QByteArray c("255");
qDebug() << b.toShort() << c.toShort();
qDebug() << *((short*)b.data()) << *((short*)c.data());
输出是:
0 255
255 13618
您可能需要根据字节序更改字节顺序。但它可以满足您的需求。
您可以使用位操纵器构建您的 qint64:
#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);
}
您可以使用QDataStream
读取二进制数据。
quint8 packed_bytes[] { 0x12, 0x34, 0x56, 0x78 };
QByteArray packed_array { QByteArray(reinterpret_cast<char*>(packed_bytes), sizeof(packed_bytes)) };
QDataStream stream(packed_array);
stream.setByteOrder(QDataStream::LittleEndian);
int result;
stream >> result;
qDebug() << QString::number(result,16);
这是一个 generic 解决方案,用于将 QByteArray
转换为 "some other type"(例如问题中特别提出的问题)运行它通过 QDataStream
(由接受的答案完成)。
DISCLAIMER: I am only advocating for using this in a private implementation. I am aware there are many ways one could abuse the
macro!
使用这个宏,你可以很容易地产生很多转换函数,比如我提供的例子。如果您需要从流中提取多种类型,以这种方式定义一系列此类函数可能会很有用。显然,您可以针对您的用例调整宏,重点是 pattern 可以保持基本相同并放入这样的宏中。
#define byteArrayToType( data, order, type ) \
QDataStream stream( data ); \
stream.setByteOrder( order ); \
type t; \
stream >> t; \
return t;
简单包装宏的示例函数:
16 位,有符号
qint16 toQInt16( const QByteArray &data,
const QDataStream::ByteOrder order=QDataStream::BigEndian )
{ byteArrayToType( data, order, qint16 ) }
32 位,有符号
qint32 toQInt32( const QByteArray &data,
const QDataStream::ByteOrder order=QDataStream::BigEndian )
{ byteArrayToType( data, order, qint32 ) }
64 位,有符号
qint64 toQInt64( const QByteArray &data,
const QDataStream::ByteOrder order=QDataStream::BigEndian )
{ byteArrayToType( data, order, qint64 ) }
将字节数组转换为所需格式并使用built-in 函数qFromBigEndian
或qFromLittleEndian
设置字节顺序。示例代码如下所示,
QByteArray byteArray("\x45\x09\x03\x00");
quint32 myValue = qFromBigEndian<quint32>(byteArray);
qDebug() << "Hex value: " << QString("0x%1").arg(myValue, 8, 16, QLatin1Char( '0' ));
myValue
保留转换后的值。
不要忘记包含头文件<QtEndian>
我正在使用串行通信,我在 QByteArray
中接收到 32 位整数,这些整数被打包成 4 个单独的字节(小端)。
我尝试使用 QByteArray::toLong()
从 4 个字节中解压值,但转换失败并且 returns 错误的数字:
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
预期的 unpacked_value
是 0x78563412(小端解包)。为什么转换失败?
toLong()
将 char * digits string
转换为 long。不是字节。并且您的值可能不会构成字符串“0x78563412”或其等效的十进制值。因此结果为 0。
如果您需要解释字节值,只要您可以执行以下操作:
long value;
value == *((long*)packed_bytes.data());
或者访问一个字节数组作为长数组:
long * values;
values == (long*)packed_bytes.data();
values[0]; // contains first long
values[1]; // contains second long
...
不知道我的例子是否开箱即用,但应该说清楚了原理。
看看这个例子:
char bytes[] = {255, 0};
QByteArray b(bytes, 2);
QByteArray c("255");
qDebug() << b.toShort() << c.toShort();
qDebug() << *((short*)b.data()) << *((short*)c.data());
输出是:
0 255
255 13618
您可能需要根据字节序更改字节顺序。但它可以满足您的需求。
您可以使用位操纵器构建您的 qint64:
#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);
}
您可以使用QDataStream
读取二进制数据。
quint8 packed_bytes[] { 0x12, 0x34, 0x56, 0x78 };
QByteArray packed_array { QByteArray(reinterpret_cast<char*>(packed_bytes), sizeof(packed_bytes)) };
QDataStream stream(packed_array);
stream.setByteOrder(QDataStream::LittleEndian);
int result;
stream >> result;
qDebug() << QString::number(result,16);
这是一个 generic 解决方案,用于将 QByteArray
转换为 "some other type"(例如问题中特别提出的问题)运行它通过 QDataStream
(由接受的答案完成)。
DISCLAIMER: I am only advocating for using this in a private implementation. I am aware there are many ways one could abuse the macro!
使用这个宏,你可以很容易地产生很多转换函数,比如我提供的例子。如果您需要从流中提取多种类型,以这种方式定义一系列此类函数可能会很有用。显然,您可以针对您的用例调整宏,重点是 pattern 可以保持基本相同并放入这样的宏中。
#define byteArrayToType( data, order, type ) \
QDataStream stream( data ); \
stream.setByteOrder( order ); \
type t; \
stream >> t; \
return t;
简单包装宏的示例函数:
16 位,有符号
qint16 toQInt16( const QByteArray &data,
const QDataStream::ByteOrder order=QDataStream::BigEndian )
{ byteArrayToType( data, order, qint16 ) }
32 位,有符号
qint32 toQInt32( const QByteArray &data,
const QDataStream::ByteOrder order=QDataStream::BigEndian )
{ byteArrayToType( data, order, qint32 ) }
64 位,有符号
qint64 toQInt64( const QByteArray &data,
const QDataStream::ByteOrder order=QDataStream::BigEndian )
{ byteArrayToType( data, order, qint64 ) }
将字节数组转换为所需格式并使用built-in 函数qFromBigEndian
或qFromLittleEndian
设置字节顺序。示例代码如下所示,
QByteArray byteArray("\x45\x09\x03\x00");
quint32 myValue = qFromBigEndian<quint32>(byteArray);
qDebug() << "Hex value: " << QString("0x%1").arg(myValue, 8, 16, QLatin1Char( '0' ));
myValue
保留转换后的值。
不要忘记包含头文件<QtEndian>