QDataStream не будет работать с пользовательским массивом символов - PullRequest
1 голос
/ 29 января 2012

У меня есть приложение, которое состоит из двух основных модулей. Один написан на C, использует стандартную библиотеку времени выполнения C, а другой написан на Qt C ++. Они общаются друг с другом с помощью IPC. Модуль C создает массив символов, заполняет его данными и отправляет в модуль, написанный на Qt. Я хочу десериализовать полученные данные, используя QDataStream, но мои усилия пока не дали никакого результата. Вот простой пример того, чего я пытаюсь достичь:

unsigned int pointer = 0;
const int IPC_MSG_LEN = 500;
const int IPC_MSG_HEADER = 200;
const int SOMETHING = 1443;
char api = 55;

char msg[IPC_MSG_LEN] = {0};
memcpy_s(msg, IPC_MSG_LEN, &IPC_MSG_HEADER, sizeof(int));
pointer = sizeof(unsigned int);
memcpy_s(&msg[pointer], IPC_MSG_LEN - pointer, &api, sizeof(char));
++pointer;
memcpy_s(&msg[pointer], IPC_MSG_LEN - pointer, &SOMETHING, sizeof(int));

QByteArray arr(msg, IPC_MSG_LEN);
QDataStream ds(&arr, QIODevice::ReadOnly);
qint32 header = 0, aa = 0;
qint8 t_api = 0;
ds >> header; //Doesn't work
ds >> t_api; //Works
ds >> aa; //Doesn't work

Как видите, код довольно прост, но переменные header и aa десериализуются в случайное число. Однако t_api (однобайтовая переменная) имеет правильное назначенное значение. Так в чем же проблема с этим кодом? Использует ли QDataStream закрытый формат данных, который не совместим с тем, который я использую? Должен ли я написать свою собственную реализацию QIODevice или есть быстрое исправление, о котором я не знаю? :) Спасибо, я ценю вашу помощь.

UPDATE


Большое спасибо, ребята, ваше решение отлично работает с этими примитивными типами данных, но проблема в том, что мне также нужно иметь возможность сериализовать / десериализовать строки char *.

wchar_t* name1 = L"something";
memcpy_s(&msg[pointer], IPC_MSG_LEN - pointer, name1, (wcslen(name1) + 1) * 2);

char* ai = new char[500];
ds >> ai; //ai becomes NULL here :|

Есть ли способ достичь этого? Еще раз спасибо

Ответы [ 2 ]

3 голосов
/ 29 января 2012
QDataStream::setByteOrder(QDataStream::LittleEndian);

#include <QDebug>
#include <QByteArray>
#include <QDataStream>
#include <QString>
#include <vector>

template<typename T> void writePtr(char*&dst, T data){
    *reinterpret_cast<T*>(dst) = data;
    dst += sizeof(T);
}

int main(int argc, char** argv){
    const size_t ipcSize = 512;
    std::vector<char> buffer(ipcSize, 0);
    quint32 sendVal1 = 0x12345678, recvVal1 = 0;
    quint8 sendVal2 = 0xee, recvVal2 = 0;   
    quint32 sendVal3 = 0x9999abcd, recvVal3 = 0;
    char* dst = &buffer[0];
    writePtr(dst, sendVal1);
    writePtr(dst, sendVal2);
    writePtr(dst, sendVal3);

    QByteArray byteArray(&buffer[0]);
    QDataStream stream(&byteArray, QIODevice::ReadOnly);
    stream.setByteOrder(QDataStream::LittleEndian);

    stream >> recvVal1 >> recvVal2 >> recvVal3;

    qDebug() << QString(QObject::tr("sent: %1, received: %2")).arg(sendVal1, 8, 16).arg    (recvVal1, 8, 16);
    qDebug() << QString(QObject::tr("sent: %1, received: %2")).arg(sendVal2, 2, 16).arg(recvVal2, 2, 16);
    qDebug() << QString(QObject::tr("sent: %1, received: %2")).arg(sendVal3, 8, 16).arg(recvVal3, 8, 16);

    return 0;
}

но проблема в том, что мне также нужно иметь возможность сериализации / десериализации строк char *.

Сериализация данных Qtформат поясняется (подробно) здесь .Вы ДОЛЖНЫ прочитать этот документ, если хотите использовать QDataStream для IPC.У Qt хорошая документация , так что используйте ее.

Также это не строка char *:

 wchar_t* name1 = L"something";

Это строка wchar_t*.

wchar_t имеет разный размер в зависимости от компилятора - 4 или 2 байта на wchar_t.Что означает проблему для IPC.в отличие от wchar_t, char гарантированно будет иметь размер 1 байт.Поэтому либо закодируйте всю строку в UTF8 (или используйте 8-битную строку с известной кодовой страницей / кодировкой) и запишите ее в виде необработанных данных в QByteArray-совместимый формат :

void writeDataPtr(char*& ptr, const char* data, quint32 size){
    if (!data){
        size = 0xffffffff;
        writePtr(ptr, size);
        return;
    }

    memcpy(ptr, data, size);
    ptr += size;
}

Затем используйте QString::fromUtf8 для декодирования (или QTextCodec - если вы решили использовать другую 8-битную кодировку вместо utf8).ИЛИ если , вы можете убедиться, что ваша строка wchar_t* соответствует UTF16 и sizeof(wchar_t) == 2, выгрузите ее в QString-совместимый формат .

Кстати - на вашем месте я бы избежал memcpy_s.Это не является частью стандарта C ++, что является очень веской причиной, чтобы его избегать.


Я хочу прочитать wchar_t * / char * из QDataStream, пока позиция потока не достигнет нулевого завершающего символа.

Если это домашняя работа, пометьте свой пост соответствующим образом.

Один из них должен работать:

QString readWcharString(QDataStream& stream){
    QVector<ushort> rawData;
    ushort tmp;
    do{
        stream >> tmp;
        rawData.push_back(tmp)
    }while(tmp);
    return QString::fromUtf16(rawData.data());
}

или

QString readWcharString(QDataStream& stream){
    QVector<wchar_t> rawData;
    ushort tmp;
    do{
        stream >> tmp;
        rawData.push_back(tmp)
    }while(tmp);
    return QString::fromWCharArray(rawData.data());
}
3 голосов
/ 29 января 2012

QDataStream по умолчанию сохраняет числа в формате с прямым порядком байтов.
Вы можете изменить это с помощью:

ds.setByteOrder(QDataStream::ByteOrder(QSysInfo::ByteOrder));

, который вместо этого будет использовать обнаруженный порядок байтов хоста.

...