本文介绍了将QByteArray强制转换为`long'会对同一输入输出不同的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



代码的目的是测试一个函数,该函数将一个值打包成4个字节,并解包成一个32位的值。 value1 value2 value3 code> test_unpack()是2018915346(即0x78563412,因为little-endian解包)。我有这种从解压缩的方法。下面是一个MCV示例,您可以轻松地构建和看到自己的问题。注意,如果你注释掉了 test1() test_unpack()的正文, p>

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; // outputs32651099317351442(不正确的值)

quint8 b_bytes [] = {0x12,0x34,0x56,0x78};
QByteArray b = QByteArray(reinterpret_cast< char *>(b_bytes),4);
long value2 = *((long *)b.data());
qDebug()<< value2; // outputs2018915346(正确的值)

quint8 c_bytes [] = {0x12,0x34,0x56,0x78};
QByteArray c = QByteArray(reinterpret_cast< char *>(c_bytes),4);
long value3 = *((long *)c.data());
qDebug()<< value3; // outputs2018915346(正确的值)

返回value1;
}

void TestCanSerialComm :: test1()
{
QCOMPARE(aoeu,aoeu); //如果你评论这一行,下一个测试将通过,如预期。
}

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

test_canserialcomm.h
$ b

  #ifndef TEST_CANSERIALCOMM_H 
#define TEST_CANSERIALCOMM_H
#include< QtTest>

class TestCanSerialComm:public QObject
{
Q_OBJECT
私有插槽:
void test1();
void test_unpack();
};
#endif // TEST_CANSERIALCOMM_H

test_main.cpp p>

  #include< QtTest> 
#includetest_canserialcomm.h
#include< QCoreApplication>

int main(int argc,char ** argv){
QCoreApplication app(argc,argv);
TestCanSerialComm testCanSerialComm;
//执行测试程序。
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 错误的值。



任何想法为什么会发生这种情况?

如果我添加一行 qDebug()<< ;

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



修复是使用一个类型,大小,例如 std :: int32_t



另外,使用 *((long *) [...])到alias内存不能保证工作,主要是因为对齐问题,但是(在一般情况下)因为别名只支持相当于 char 签名 unsigned 更安全的方法是使用 memcpy

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


EDIT: Added full MCV example project.

I have a strange problem where the same code and same input produce different output values.

The purpose of the code is to test a function that takes a value packed into 4 bytes, and unpack it into a single 32bit value. The expected value of value1, value2 and value3 in test_unpack() is 2018915346 (i.e. 0x78563412 because of little-endian unpacking). I got this method of unpacking from another answer. Below is an MCV example that you can easily build and see the problem for yourself. Note that if you comment out the body of test1() test_unpack() magically passes with the correct value.

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

The output of value1 in test_unpack() is wrong, despite the same code and same inputs. Strangely, if I remove the qDebug() calls and set a breakpoint, the debugger expression evaluator now shows that value2 has the wrong value.

Any idea why this is happening? Or even how to troubleshoot this further?

Additional Notes: If I add a line qDebug() << "garbage"; at the top of my function, all 3 values produced are correct.

解决方案

You're compiling and running this program on a system where long is 8 bytes, but your QByteArray has only 4 bytes. That means that when you alias the array as a long (using *((long*)a.data())) you're reading 4 bytes past the end of the array, into uninitialized heap storage.

The fix is to use a type that is guaranteed to be 4 bytes in size, e.g. std::int32_t.

As an aside, using *((long*)[...]) to alias memory is not guaranteed to work, primarily because of alignment issues but also (in the general case) because aliasing is only supported for types equivalent to char or a signed or unsigned variant. The safer technique is to use memcpy:

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

这篇关于将QByteArray强制转换为`long'会对同一输入输出不同的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-01 18:02