Seite 1 von 1

QByteArray* als Funktionsparameter

Verfasst: 10. September 2015 14:56
von leif
Hallo,

mein Problem: Ich übergebe die Referenz auf einen QByteArray an eine Funktion als Parameter. Darin soll es befüllt werden. Die Daten kommen von einem Aufruf der read-Funktionen der QSerialPort-Klasse. Auch wenn die Länge des QByteArray danach meiner Erwartung entspricht, kann ich mit den enthaltenen Daten nichts anfangen.

Code: Alles auswählen

Library *lib = new Library;
QSerialPort *port = new QSerialPort("COM1");
QByteArray answer;

int err = lib->readAnswer(port, &answer);
if(err < 0) return;
QDatastream out(&answer, QIODevice::ReadOnly);
int data;
out >> data;
Hier ist der ursprüngliche Anlauf. Nach dem append der QByteArray-Klasse kann ich sowohl innerhalb der folgenden Funktion nichts mit den enthaltenen Daten anfangen, weil sie nur Murks sind, wenn ich sie mit einem QDatastream wie oben extrahiere, als auch an obiger Stelle des Aufrufs.

Code: Alles auswählen

int Library::readAnswer(QSerialPort *port, QByteArray *answer)
{
  int count = port->bytesAvailable();
  if(count < 1) return -1;
  char *temp = new char[count];
  port->read(temp, count);
  answer->append(temp, count);
  delete [] temp;
  return 0;
}
In der folgenden Variante kann ich immerhin innerhalb der Funktion mit den Daten etwas anfangen, extrahiere ich sie mit QDatastream, versuche ich es aber wie gehabt an der Stelle des Aufrufs, bleibt wieder nur Murks.

Code: Alles auswählen

int Library::readAnswer(QSerialPort *port, QByteArray *answer)
{
        int count = port->bytesAvailable();
        char *temp = new char[count];
        port->read(temp, count);
        QBuffer buffer(data_read);
        buffer.open(QIODevice::ReadWrite);
        QDataStream out(&buffer);
        out.writeRawData(temp, count);
        buffer.close();
        delete [] temp;
        return 0;
}
Ich denke mir, das muss doch gehen, aber wie?

Grüße,
leif

Re: QByteArray* als Funktionsparameter

Verfasst: 10. September 2015 16:05
von bobcat
Könnte es am Encoding der bytes liegen? (Was heißt "Murks"?)

Re: QByteArray* als Funktionsparameter

Verfasst: 10. September 2015 16:28
von leif
Im zweiten Anlauf habe ich unmittelbar nach

Code: Alles auswählen

        out.writeRawData(temp, count);

Code: Alles auswählen

        short data;
        out >> data;
        qDebug() << data;
stehen. Wenn ich mir den Wert von data mit qDebug() so innerhalb der Funktion zurückgeben lasse, erhalte wie erwartet 0.
Wenn ich aber mit QDataStream(&ba) nach dem Funktionsaufruf den data-Wert lese, erhalte ich 1024.
Wenn ich temp mit memcpy() innerhalb der Funktion auf den short-Wert data kopiere, erhalte ich auch wie erwartet 0.

Re: QByteArray* als Funktionsparameter

Verfasst: 10. September 2015 18:02
von Christian81
Was spricht gegen ein einfaches

Code: Alles auswählen

QByteArray ba = port->readAll();
anstatt der komischen Funktion?

/edit: Abgesehen davon - sind die Daten die aus dem QSerialPort kommen wirklich mit QDataStream codiert? Ich bezweifele das stark ...

Re: QByteArray* als Funktionsparameter

Verfasst: 11. September 2015 17:31
von leif
Hmm, leider ist der Beitrag weg. Egal, denn am Ende habe ich es auf einem anderen Rechner nochmal ausprobiert. Die Qt-Version sollte dieselbe sein, aber das Ergebnis ist wie erhofft. Im Prinzip geht es mir ja darum, das QByteArray durch eine Funktion aufzufüllen.

Code: Alles auswählen

#include <QDebug>

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    QByteArray ba;
    ba.append("Hu");
    fillUp(&ba);

    qDebug() << ba;
}

void MainWindow::fillUp(QByteArray *ba)
{
//    try#1
//    ba->append("hu");

//    try#2
    ba->resize(4);
    strncpy(ba->data() + 2, "hu", 2);
}
Beide Varianten try# funktionieren wie sie sollen. Ich bin ganz sicher, dass das an dem Rechner gestern nicht ging.

Re: QByteArray* als Funktionsparameter

Verfasst: 11. September 2015 20:07
von Christian81
dann eben

Code: Alles auswählen

ba->append(port.readAll());
Alles andere ist überflüssig

Re: QByteArray* als Funktionsparameter

Verfasst: 14. September 2015 09:40
von leif
Danke, genau das habe ich irgendwie vermisst.
Ich verstehe jetzt auch, was mit Kodierung gemeint ist. Das war mir Ende letzter Woche nicht mehr klar geworden. Vielleicht möchte mir da noch jemand etwas nachhelfen es richtig zu festigen.

Ich kann ein QByteArray nicht mit QDatastream in seine Bestandteile zerlegen, wenn es nicht von vornherein schon mit Hilfe eines QDatastreams zusammengesetzt worden ist.

Das ist das eine, das andere ist, wie ich es denn jetzt auseinandernehmen kann. Dazu müsste ich jetzt mit left(), mid() und right() die einzelnen Bytes wieder zu Datentypen zusammensetzen, sprich char*, short, long, usw. extrahieren. Das erscheint mir etwas umständlich, wobei ja auch in ein Struct herauskopiert werden könnte. Nun, ich denke, ich bin soweit auch schon zufrieden und möchte das Thema nicht weiter strapazieren.

Edit: Anstelle von herauskopiert, verwende ich einen Cast.

Code: Alles auswählen

myStruct *struct = reinterpret_cast<myStruct*>(ba.data());

Re: QByteArray* als Funktionsparameter

Verfasst: 14. September 2015 19:11
von Christian81
Ein Datenstream besteht nunmal aus einer Ansammlung von Zeichen die korrekt interpretiert werden müssen. Nennt sich Protokoll. Und zum (De)Serialisieren muss man eben diesen Datenstream bearbeiten.

Re: QByteArray* als Funktionsparameter

Verfasst: 16. September 2015 09:29
von RHBaum
myStruct *struct = reinterpret_cast<myStruct*>(ba.data());
Ist ab und an sogar übliches vorgehen.
Aber man muss beachten, das das nur zuverlaessig funktioniert, wenn das speicherabbild des structs beim sender und empfänger binaerkompatibel ist.
Bei Binaerkompatiblität spielen dann so gewisse faktoren rein (endianess, definition der datentypen, Memory alignment).
Das schlimme daran ist, manches ist von der Platform, manches vom compiler, und manches von compiler-einstellungen abhängig.

Sicher das das funktioniert kann man dann nur sein, wenn sender und empfänger ausm gleichen compilerlauf kommen, und die platform definitiv nicht geswitcht wird.
Also für Computer zu computer verbindungen nur bedingt geeignet, da platform compiler und version passen müssten,
von zwei programmen innerhalb eines comps, sollt man sich sicher sein, das die vom selben compiler/version/ einstellung kommen, am besten selbes binary -> dlls.
Innerhalb eines programmes auf nem comp sollt es kein problem sein (macht es dann aber sinn, dann gehen auch referenzen^^)
Beim serializieren (ablegen auf der platte) sollt man sowas soweiso durch Hashes / versionierung schuetzen ....

QDataStream ist dagegen ein höheres Protokoll, bzw benutzt ein solches Protokoll, was sicherstellt das darin serialisierte Daten auf allen Qt plattformen gleich interpretiert werden.
Dafuer arbeitet es aehnlich wie google Protokollpuffer (binär), json, xml (text) ... es legt tags an, schreibt die daten zwischen die tags, benutzt eine einheitliche byteorder, und versionen.
Das ganze auch binaer ... dadurch kann nur Qdatastream das zeugs lesen .... bzw. die Qt doc laesst sich da über internas ned so aus, so das reenginiering betreiben müsstest um das Zeugs von anderen klassen lesen zu lassen.
Dann ist aber nicht garantiert das das stabil über mehrere Qt versionen bleibt (versionierung).
WIllst das von anderen klassen lesen, dann ist QTextStream, oder höhere auf Text aufbauende Protokolle (json, xml ..... ) das mittel der wahl.

Ciao ....