2016-04-21 70 views
0

編輯:添加完整的MCV示例項目。將QByteArray投射到`long`輸出相同輸入的不同結果

我有一個奇怪的問題,其中相同的代碼和相同的輸入產生不同的輸出值。

該代碼的目的是測試一個函數,該函數將值打包成4個字節,並將其解壓縮爲單個32位值。在test_unpack()中的value1,value2value3的預期值是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 

value1test_unpack()的輸出是錯誤的,儘管相同的代碼和相同的輸入。奇怪的是,如果我刪除了qDebug()調用並設置了一個斷點,則調試器表達式求值程序現在顯示value2具有錯誤的值。

任何想法爲什麼會發生這種情況?甚至如何進一步解決這個問題?

附加說明:如果我在函數的頂部添加一行qDebug() << "garbage";,則生成的所有3個值都是正確的。

+1

看值的內存中表示,可能給一個線索(我沒有QT) - 又一想:爲什麼不能用一個簡單的工會要做到這一點? – slashmais

+0

@slashmais感謝您的提示。通過「內存中的表示」,您是否指我在設置斷點時在調試器中看到的變量值?這些值與'qDebug()'輸出相同。我不確定我在這種情況下如何使用聯合。 – DBedrenko

+0

我運行你的代碼,並得到所有三個值的相同結果。 – Paraboloid87

回答

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()); 
相關問題