Soluzione/soluzione:
Infatti, l'uscita del qDebug()
QByteArray
viene troncato al carattere '\0'
. Questo non ha nulla a che fare con il QByteArray; non puoi nemmeno emettere un carattere '\ 0' usando qDebug(). Per una spiegazione vedi sotto.
QByteArray buffer;
buffer.append("hello");
buffer.append('\0');
buffer.append("world");
qDebug() << "GNSS msg (" << buffer.size() << "): " << buffer;
uscita:
GNSS msg (11): "hello
Anche eventuali seguenti argomenti vengono ignorati:
qDebug() << "hello" << '\0' << "world";
uscita:
hello
È possibile aggirare questo "problema", sostituendo il caratteri speciali nel tuo byte array prima di loro il debug:
QByteArray dbg = buffer; // create a copy to not alter the buffer itself
dbg.replace('\\', "\\\\"); // escape the backslash itself
dbg.replace('\0', "\\0"); // get rid of 0 characters
dbg.replace('"', "\\\""); // more special characters as you like
qDebug() << "GNSS msg (" << buffer.size() << "): " << dbg; // not dbg.size()!
uscita:
GNSS msg (11): "hello\0world"
Allora, perché sta succedendo questo? Perché non riesco a produrre uno '\0'
usando qDebug()?
Entriamo nel codice interno Qt per scoprire cosa fa qDebug()
. I seguenti frammenti di codice provengono dal codice sorgente di Qt 4.8.0.
Questo metodo viene chiamato quando si esegue qDebug() << buffer
:
inline QDebug &operator<<(const QByteArray & t) {
stream->ts << '\"' << t << '\"'; return maybeSpace();
}
Il stream->ts
sopra è di tipo QTextStream
, che converte il QByteArray
in un QString
:
QTextStream &QTextStream::operator<<(const QByteArray &array)
{
Q_D(QTextStream);
CHECK_VALID_STREAM(*this);
// Here, Qt constructs a QString from the binary data. Until now,
// the '\0' and following data is still captured.
d->putString(QString::fromAscii(array.constData(), array.length()));
return *this;
}
Come si può vedere, d->putString(QString)
viene chiamato (il tipo di d
è la classe privata interna del flusso di testo), che chiama write(QString)
dopo aver eseguito alcuni padding per i campi a larghezza costante. Ho ignorare il codice di putString(QString)
e saltare direttamente in d->write(QString)
, che è definito in questo modo:
inline void QTextStreamPrivate::write(const QString &data)
{
if (string) {
string->append(data);
} else {
writeBuffer += data;
if (writeBuffer.size() > QTEXTSTREAM_BUFFERSIZE)
flushWriteBuffer();
}
}
Come si può vedere, la QTextStreamPrivate
ha un buffer. Questo buffer è di tipo QString
. Quindi cosa succede quando il buffer è finalmente stampato sul terminale? Per questo, dobbiamo scoprire cosa succede quando l'istruzione qDebug()
termina e il buffer viene passato al gestore messaggi, che, per impostazione predefinita, stampa il buffer sul terminale. Questo sta accadendo nel distruttore della classe QDebug
, che è definito come segue:
inline ~QDebug() {
if (!--stream->ref) {
if(stream->message_output) {
QT_TRY {
qt_message_output(stream->type, stream->buffer.toLocal8Bit().data());
} QT_CATCH(std::bad_alloc&) { /* We're out of memory - give up. */ }
}
delete stream;
}
}
Così qui è la parte non-binary-safe. Qt prende il buffer testuale, lo converte in rappresentazione binaria "local 8bit" (fino ad ora, AFAIK dovremmo avere ancora i dati binari che vogliamo eseguire il debug).
Tuttavia, passa al gestore di messaggi senza le specifiche aggiuntive della lunghezza dei dati binari. Come dovresti sapere, è impossibile scoprire la lunghezza di una stringa C che dovrebbe anche essere in grado di contenere i caratteri '\0'
. (Ecco perché QString::fromAscii()
nel codice sopra ha bisogno il parametro della lunghezza aggiuntiva per binary-sicurezza.)
Quindi, se si desidera gestire i '\0'
personaggi, anche la scrittura del proprio gestore di messaggi non risolverà il problema, come non si può conoscere la lunghezza. Triste ma vero.
Non vorrei citare la parola "problema", sembra davvero un bug (come evidenziato dalla chiusura mancante "dopo la stringa che normalmente qDebug aggiunge. –
@fish Penso anche che sia sufficiente troncare i dati in un" \ 0'' non è bello, d'altra parte, immagino che le uscite qDebug siano fatte per dati testuali (almeno per QString e QByteArray). Si potrebbe sostenere che in caso di un QByteArray, questo * non dovrebbe * essere supposto, ma poi si può anche sostenere che Qt potrebbe non sapere come si desidera eseguire il debug dei dati binari. L'output di un carattere zero funziona ma non si può leggerlo (che è lo scopo di qDebug()). Forse un .toHex() è la soluzione migliore per i dati binari in alcuni casi, quindi suppongo che Qt lo lasci * come * per emettere i dati – leemes
Oltre a ciò si può sostenere che questo è un comportamento corretto, sono abbastanza sicuro non era intenzionale, altrimenti lo sarebbe aggiungi il mancante ". –