qDebug не печатает полный QByteArray, содержащий двоичные данные

у меня есть QByteArray для хранения данных, полученных от GPS, который является частью двоичного и часть 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 перестает печатать, потому что у него есть предел, или потому что он достигает завершающего символа или что-то в этом роде, но я только догадываюсь.

любая помощь или объяснение такого поведения?

1 ответов


решение / обходное решение:

действительно,qDebug() выход QByteArray урезается на '' символ. Это не имеет ничего общего с QByteArray; вы даже не можете вывести символ "\0 " с помощью qDebug(). Объяснение см. ниже.

QByteArray buffer;
buffer.append("hello");
buffer.append('');
buffer.append("world");

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

выход:

GNSS msg ( 11 ):  "hello

игнорируются даже любые следующие аргументы:

qDebug() << "hello" << '' << "world";

выход:

hello

вы можете обойти это "проблема" путем замены специальных символов в вашем массиве байтов перед отладкой их:

QByteArray dbg = buffer;   // create a copy to not alter the buffer itself
dbg.replace('\', "\\"); // escape the backslash itself
dbg.replace('', "\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 ):  "helloworld" 

так почему это происходит? Почему я не могу вывести '' С помощью qDebug()?

давайте погрузимся во внутренний код Qt, чтобы узнать, что qDebug() делает. Следующие фрагменты кода взяты из исходного кода Qt 4.8.0.

этот метод вызывается, когда вы делаете qDebug() << buffer:

inline QDebug &operator<<(const QByteArray & t) {
    stream->ts  << '\"' << t << '\"'; return maybeSpace();
}

на stream->ts выше типа QTextStream, который преобразует the 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 '' 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-строки, которая также должна быть способна удерживать '' символы. (Вот почему QString::fromAscii() в коде выше нужен дополнительный параметр длины для binary-безопасность.)

Итак, если вы хотите справиться с '' символы, даже написание собственного обработчика сообщений не решит проблему, так как вы не можете знать длину. Печально, но это правда.