【问题标题】:How to unpack 32bit integer packed in a QByteArray?如何解压缩包装在 QByteArray 中的 32 位整数?
【发布时间】:2016-08-07 07:39:56
【问题描述】:

我正在使用串行通信,我在 QByteArray 中接收 32 位整数,打包在 4 个单独的字节(小端)中。 我尝试使用 QByteArray::toLong() 从 4 个字节中解压缩值,但转换失败并返回错误的数字:

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(小端解包)。为什么转换失败?

【问题讨论】:

    标签: qt type-conversion qt5 unpack qbytearray


    【解决方案1】:

    这是一个通用解决方案,通过运行QDataStreamQByteArray 转换为“其他类型”(例如问题中特别提出的内容)(由接受的答案)。

    免责声明:我只是主张在私有实现中使用它。我知道有很多方法可以滥用 宏!

    使用此宏,您可以轻松生成许多转换函数,例如我提供的示例。如果您需要从流中提取多种类型,以这种方式定义一系列此类函数可能会很有用。显然,您可以为您的用例调整宏,关键是 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 ) }
    

    【讨论】:

      【解决方案2】:

      您可以使用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);
      

      【讨论】:

        【解决方案3】:

        toLong() 将 char * 数字 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
        

        您可能需要根据字节序更改字节顺序。但它可以满足您的需求。

        【讨论】:

        • 感谢您回答我,但您在我的帖子中看到我将数组转换为 char *,它将整数转换为字符串,就像您描述的那样。我错过了什么吗?以及为什么转换失败(如bool 所示),而不是仅仅返回不正确的结果?
        • 您能否正确打印该字符串并且您看到写入的值正确吗?然后它应该工作。但是,如果字节值表示值,而不是它们的 ascii 表示,则需要类似我的方法。
        • QByteArray::toLong() 将您的字节解释为 \0 终止的字符串。
        • 嗯我不知道为什么 API 完全使用 ASCII 或者为什么它必须被 \0 终止,所以我尝试了你的解决方案,但返回的值不正确:“0x20000078563412”(无论我是将数组解包为小端还是大端,这都是错误的)。
        • 它不能被你终止为0。但是与 ascii 字符串相关的方法将被视为 0\-终止。和 toLong 作用于字符串。
        【解决方案4】:

        您可以使用位操纵器构建您的 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);
        }
        

        【讨论】:

        • 感谢您的解决方案,但它的级别相当低,只能生成无符号数字,我不确定是否可以使用它来转换例如2 字节或 3 字节值。当然,像 Qt 这样庞大的框架已经具有抽象出低级位移的功能吗?另外,我必须为此编写测试用例,所以使用 Qt 中已有的东西肯定会更好。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-21
        • 1970-01-01
        相关资源
        最近更新 更多