I have a QByteArray
to store data received from a GPS, which is part binary and part ASCII. I want to know for debug proposals know what's being received, so I'm writing a qDebug
like this:
//QByteArray buffer;
//...
qDebug() << "GNSS msg (" << buffer.size() << "): " << buffer;
And I get messages like this at console:
GNSS msg ( 1774 ): "ygnnsdgk...(many data)..PR085hlHJGOLH
(more data into a new line, which is OK because it is a new GNSS sentence and
probably has a \n at the end of each one) blablabla...
But suddenly I get a new print iteration. Data has not been erased yet, it has been appended. So new message size its for example 3204, bigger than the previous print obviously. But it prints exactly the same (but with the new size 3204 between brackets). No new data is printed, just the same as the previous message had:
GNSS msg ( 3204 ): "ygnnsdgk...(many data)..PR085hlHJGOLH
(more data into a new line, which is OK because it is a new GNSS sentence and
probably has a \n at the end of each one) blablabla...
I guess qDebug
stops printing because it has a limit, or because it reaches a terminating character or something like that, but I'm only guessing.
Any help or explanation for this behaviour?
Solution / workaround:
Indeed, the
qDebug()
output ofQByteArray
gets truncated at a'\0'
character. This doesn't have something to do with the QByteArray; you even can't ever output a '\0' character using qDebug(). For an explanation see below.Output:
Even any following arguments are ignored:
Output:
You can work around this "problem" by replacing the special characters in your byte array before debugging them:
Output:
So why is this happening? Why can't I output a
'\0'
using qDebug()?Let's dive into the Qt internal code to find out what
qDebug()
does. The following code snippets are from the Qt 4.8.0 source code.This method is called when you do
qDebug() << buffer
:The
stream->ts
above is of typeQTextStream
, which converts theQByteArray
into aQString
:As you can see,
d->putString(QString)
is called (the type ofd
is the internal private class of the text stream), which callswrite(QString)
after doing some padding for constant-width fields. I skip the code ofputString(QString)
and directly jump intod->write(QString)
, which is defined like this:As you can see, the
QTextStreamPrivate
has a buffer. This buffer is of typeQString
. So what happens when the buffer is finally printed on the terminal? For this, we have to find out what happens when yourqDebug()
statement finishes and the buffer is passed to the message handler, which, per default, prints the buffer on the terminal. This is happening in the destructor of theQDebug
class, which is defined as follows:So here is the non-binary-safe part. Qt takes the textual buffer, converts it to "local 8bit" binary representation (until now, AFAIK we should still have the binary data we want to debug).
But then passes it to the message handler without the additional specification of the length of the binary data. As you should know, it is impossible to find out the length of a C-string which should also be able to hold
'\0'
characters. (That's whyQString::fromAscii()
in the code above needs the additional length parameter for binary-safety.)So if you want to handle the
'\0'
characters, even writing your own message handler will not solve the problem, as you can't know the length. Sad, but true.