首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >qDebug未打印包含二进制数据的完整QByteArray

qDebug未打印包含二进制数据的完整QByteArray
EN

Stack Overflow用户
提问于 2012-06-06 19:18:55
回答 1查看 12.4K关注 0票数 12

我有一个QByteArray来存储从全球定位系统接收的数据,它部分是二进制的,部分是ASCII码。我想知道调试建议正在接收什么,所以我编写了一个qDebug,如下所示:

代码语言:javascript
复制
//QByteArray buffer;
//...
qDebug() << "GNSS msg (" << buffer.size() << "): " << buffer;

我在控制台上收到了这样的消息:

代码语言:javascript
复制
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 )。不会打印新数据,与前一条消息相同:

代码语言:javascript
复制
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停止打印是因为它有一个限制,或者因为它到达了一个终止字符或类似的东西,但我只是猜测。

对这种行为有什么帮助或解释吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-06-06 21:02:00

解决方案/解决方法:

实际上,QByteArrayqDebug()输出在'\0'字符处被截断。这与QByteArray无关;您甚至不能使用qDebug()输出'\0‘字符。有关解释,请参见下面的说明。

代码语言:javascript
复制
QByteArray buffer;
buffer.append("hello");
buffer.append('\0');
buffer.append("world");

qDebug() << "GNSS msg (" << buffer.size() << "): " << buffer;

输出:

代码语言:javascript
复制
GNSS msg ( 11 ):  "hello

甚至忽略以下任何参数:

代码语言:javascript
复制
qDebug() << "hello" << '\0' << "world";

输出:

代码语言:javascript
复制
hello

您可以通过在调试字节数组之前替换字节数组中的特殊字符来解决此“问题”:

代码语言:javascript
复制
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()!

输出:

代码语言:javascript
复制
GNSS msg ( 11 ):  "hello\0world" 

那么为什么会发生这种情况呢?为什么我不能使用qDebug()输出 '\0'

让我们深入研究一下Qt内部代码,看看qDebug()是做什么的。以下代码片段来自Qt 4.8.0源代码。

此方法在执行qDebug() << buffer时调用

代码语言:javascript
复制
inline QDebug &operator<<(const QByteArray & t) {
    stream->ts  << '\"' << t << '\"'; return maybeSpace();
}

上面的stream->ts的类型为QTextStream,它将QByteArray转换为QString

代码语言:javascript
复制
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),它的定义如下:

代码语言:javascript
复制
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类的析构函数中,其定义如下:

代码语言:javascript
复制
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'字符,即使编写自己的消息处理程序也不能解决问题,因为您不知道长度。很悲哀,但这是真的。

票数 23
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10913155

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档