解決策/回避策:
実際、 のqDebug()
出力は文字QByteArray
で切り捨てられ'\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"
では、なぜこれが起こっているのですか?'\0'
qDebug() を使用して出力できないのはなぜですか?
Qt の内部コードに飛び込んで、何qDebug()
が行われているかを調べてみましょう。次のコード スニペットは、Qt 4.8.0 ソース コードからのものです。
このメソッドは、次の場合に呼び出されますqDebug() << buffer
。
inline QDebug &operator<<(const QByteArray & t) {
stream->ts << '\"' << t << '\"'; return maybeSpace();
}
上記stream->ts
は typeQTextStream
であり、 を に変換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 ビット」バイナリ表現に変換します (これまでのところ、デバッグしたいバイナリ データがまだ残っているはずです)。
ただし、バイナリ データの長さを追加指定せずにメッセージ ハンドラに渡します。ご存知のように、文字を保持できるはずの C 文字列の長さを知ることは不可能'\0'
です。(そのためQString::fromAscii()
、上記のコードでは、バイナリ セーフのために追加の長さパラメーターが必要です。)
したがって、文字を処理したい場合は'\0'
、独自のメッセージ ハンドラーを作成しても、長さが分からないため、問題は解決しません。悲しいけれど事実です。