我有一个QByteArray来存储从全球定位系统接收的数据,它部分是二进制的,部分是ASCII码。我想知道调试建议正在接收什么,所以我编写了一个qDebug,如下所示:
//QByteArray buffer;
//...
qDebug() << "GNSS msg (" << buffer.size() << "): " << buffer;我在控制台上收到了这样的消息:
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...但是突然我得到了一个新的打印迭代。数据尚未被擦除,已被追加。例如,新的消息大小为3204,明显大于之前的打印大小。但它打印的内容完全相同(只是在括号之间使用了新尺寸3204 )。不会打印新数据,与前一条消息相同:
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...我猜qDebug停止打印是因为它有一个限制,或者因为它到达了一个终止字符或类似的东西,但我只是猜测。
对这种行为有什么帮助或解释吗?
发布于 2012-06-06 21:02:00
解决方案/解决方法:
实际上,QByteArray的qDebug()输出在'\0'字符处被截断。这与QByteArray无关;您甚至不能使用qDebug()输出'\0‘字符。有关解释,请参见下面的说明。
QByteArray buffer;
buffer.append("hello");
buffer.append('\0');
buffer.append("world");
qDebug() << "GNSS msg (" << buffer.size() << "): " << buffer;输出:
GNSS msg ( 11 ): "hello甚至忽略以下任何参数:
qDebug() << "hello" << '\0' << "world";输出:
hello您可以通过在调试字节数组之前替换字节数组中的特殊字符来解决此“问题”:
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()!输出:
GNSS msg ( 11 ): "hello\0world" 那么为什么会发生这种情况呢?为什么我不能使用qDebug()输出 '\0' ?
让我们深入研究一下Qt内部代码,看看qDebug()是做什么的。以下代码片段来自Qt 4.8.0源代码。
此方法在执行qDebug() << buffer时调用
inline QDebug &operator<<(const QByteArray & t) {
stream->ts << '\"' << t << '\"'; return maybeSpace();
}上面的stream->ts的类型为QTextStream,它将QByteArray转换为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;
}正如您所看到的,d->putString(QString)被调用( d的类型是文本流的内部私有类),它在对固定宽度的字段进行一些填充之后调用write(QString)。我跳过putString(QString)的代码,直接跳到d->write(QString),它的定义如下:
inline void QTextStreamPrivate::write(const QString &data)
{
if (string) {
string->append(data);
} else {
writeBuffer += data;
if (writeBuffer.size() > QTEXTSTREAM_BUFFERSIZE)
flushWriteBuffer();
}
}如您所见,QTextStreamPrivate有一个缓冲区。此缓冲区的类型为QString。那么,当缓冲区最终打印到终端上时会发生什么呢?为此,我们必须弄清楚当qDebug()语句完成并将缓冲区传递给消息处理程序时会发生什么情况,默认情况下,消息处理程序会在终端上打印缓冲区。这发生在QDebug类的析构函数中,其定义如下:
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;
}
}所以这里是非二进制安全的部分。Qt获取文本缓冲区,将其转换为“本地8位”二进制表示形式(到目前为止,AFAIK我们仍然有我们想要调试的二进制数据)。
但随后将其传递给消息处理器,而不需要额外指定二进制数据的长度。正如您应该知道的,不可能找出C字符串的长度,它也应该能够保存'\0'字符。(这就是为什么上面的代码中的QString::fromAscii()需要额外的长度参数来保证二进制安全性。)
因此,如果您想要处理'\0'字符,即使编写自己的消息处理程序也不能解决问题,因为您不知道长度。很悲哀,但这是真的。
https://stackoverflow.com/questions/10913155
复制相似问题