c++ - 将 QByteArray 转换为 `long` 输出相同输入的不同结果

标签 c++ qt casting qt5.6

编辑:添加了完整的 MCV 示例项目。

我有一个奇怪的问题,相同的代码和相同的输入产生不同的输出值。

该代码的目的是测试一个函数,该函数将一个值打包成 4 个字节,并将其解包为一个 32 位值。 value1的期望值, value2value3test_unpack()是 2018915346(即 0x78563412 因为小端解包)。我从another answer得到了这种解包方法.下面是一个 MCV 示例,您可以轻松构建它并亲自查看问题。请注意,如果您注释掉 test1() 的正文test_unpack()神奇地传递了正确的值。

test_canserialcomm.cpp

#include "test_canserialcomm.h"

#include <QtTest/QtTest>
#include <QByteArray>

long unpack() noexcept
{
    quint8 a_bytes[] = {0x12, 0x34, 0x56, 0x78};
    QByteArray a = QByteArray(reinterpret_cast<char*>(a_bytes), 4);
    long value1 = *((long*)a.data());
    qDebug() <<  value1; // outputs "32651099317351442" (incorrect value)

    quint8 b_bytes[] = {0x12, 0x34, 0x56, 0x78};
    QByteArray b = QByteArray(reinterpret_cast<char*>(b_bytes), 4);
    long value2 = *((long*)b.data());
    qDebug() << value2; // outputs "2018915346" (correct value)

    quint8 c_bytes[] = {0x12, 0x34, 0x56, 0x78};
    QByteArray c = QByteArray(reinterpret_cast<char*>(c_bytes), 4);
    long value3 = *((long*)c.data());
    qDebug() << value3; // outputs "2018915346" (correct value)

    return value1;
}

void TestCanSerialComm::test1()
{
    QCOMPARE("aoeu", "aoeu"); // If you comment this line, the next test will pass, as expected.
}

void TestCanSerialComm::test_unpack()
{
    long expected {0x78563412};
    QCOMPARE(unpack(), expected);
}

test_canserialcomm.h

#ifndef TEST_CANSERIALCOMM_H
#define TEST_CANSERIALCOMM_H
#include <QtTest>

class TestCanSerialComm: public QObject
{
    Q_OBJECT
private slots:
    void test1();
    void test_unpack();
};
#endif // TEST_CANSERIALCOMM_H

test_main.cpp

#include <QtTest>
#include "test_canserialcomm.h"
#include <QCoreApplication>

int main(int argc, char** argv) {
    QCoreApplication app(argc, argv);
    TestCanSerialComm testCanSerialComm;
    // Execute test-runner.
    return QTest::qExec(&testCanSerialComm, argc, argv); }

tmp.pro

QT += core \
    testlib
QT -= gui
CONFIG += c++11

TARGET = tmp
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
TARGET = UnitTests

HEADERS += test_canserialcomm.h
SOURCES += test_canserialcomm.cpp \
    test_main.cpp

value1 的输出在 test_unpack()是错误的,尽管有相同的代码和相同的输入。奇怪的是,如果我删除 qDebug()调用并设置断点,调试器表达式计算器现在显示 value2有错误的值(value)。

知道为什么会这样吗?甚至如何进一步解决此问题?

附加说明:如果我添加一行 qDebug() << "garbage";在我的函数顶部,生成的所有 3 个值都是正确的。

最佳答案

您正在 long 为 8 个字节的系统上编译和运行此程序,但您的 QByteArray 只有 4 个字节。这意味着当您将数组别名为 long(使用 *((long*)a.data()))时,您正在读取数组末尾后的 4 个字节数组,进入未初始化的堆存储。

修复方法是使用保证大小为 4 字节的类型,例如std::int32_t

顺便说一句,使用 *((long*)[...]) 来别名内存不能保证工作,主要是因为对齐问题,但也(在一般情况下)因为只有等同于 charsignedunsigned 变体的类型才支持别名。更安全的技术是使用 memcpy:

std::uint32_t value1;
assert(a.size() == sizeof(value1));
memcpy(&value1, a.data(), a.size());

关于c++ - 将 QByteArray 转换为 `long` 输出相同输入的不同结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36765576/

相关文章:

c - 一些 C++ 转换为 C,仍然遵循标准?

java - 在 XPath 1.0 中将整数转换为 double

c++ - 在 C++0x 中压缩垃圾收集器的实现

c++ - 有没有办法到达最后的盒子 - GRAPH

c++ - 可能错误使用赋值运算符代替比较运算符的地方 , = Vs ==

c++ - 使用 boost 序列化多态类

c++ - Qt 5.3 连接 lambda

c++ - 在 Qt 中如何将单例实例连接到插槽?

qt - 如何在 QCustomPlot 中隐藏网格并仅显示零线?

sql-server - MS SQL 2008 将 null 转换为字符串