QString and Embedded Nulls

Viewed 322

From https://doc.qt.io/qt-5/qstring.html

"A QString can embed '\0' characters (QChar::Null). The size() function always returns the size of the whole string, including embedded '\0' characters."

Yet I am observing:

QString frameDataAsString =
    "SEND\n"
    "content-length:23\n\n"
    "Before a Null\0And after";

and in GDB:

(gdb) p frameDataAsString
$1 = "SEND\ncontent-length:23\n\nBefore a Null"
(gdb) p frameDataAsString.size()
$2 = 37

How then, does one "embed a NULL" into the string?

2 Answers

The constructor QString::QString(const char*) cannot be used to embed \0 characters. It will copy the the passed argument just until the first 0 terminator (regardless whether it was encoded explicitly or appended implicitly).

I considered to use a temporary QByteArray but the doc. (QString::QString(const QByteArray &ba) ) mentions that the resp. constructor QString::QString(const QByteArray&) will consider 0 terminators as well.

Surprisingly, the QString::from functions (e.g. QString::fromLatin1(), QString::fromUtf8()) seem to consider the passed length correctly.

The OP found yet another method – using the QStringLiteral(). It can be applied exclusively to C string literals.

Demo:

// Qt header:
#include <QtCore>

// main application
int main()
{
  const char cstr[] = "A string with a \0 inside.";
  const size_t sizeCStr = sizeof cstr / sizeof *cstr, lenCStr = sizeCStr - 1;
  const QByteArray qBytes(cstr, sizeCStr);
  qDebug() << "qBytes:" << qBytes << "length:" << qBytes.size();
  const QString qStr0(qBytes);
  qDebug() << "qStr0:" << qStr0 << "length:" << qStr0.size();
  const QString qStr1 = QString::fromLatin1(cstr, sizeCStr);
  qDebug() << "qStr1:" << qStr1 << "length:" << qStr1.size();
  const QString qStr2 = QString::fromUtf8(cstr, sizeCStr);
  qDebug() << "qStr2:" << qStr2 << "length:" << qStr2.size();
  const QString qStrL(QStringLiteral("A string with a \0 inside."));
  qDebug() << "qStrL:" << qStrL << "length:" << qStrL.size();
}

Output:

qBytes: "A string with a \x00 inside.\x00" length: 26
qStr0: "A string with a " length: 16
qStr1: "A string with a \u0000 inside.\u0000" length: 26
qStr2: "A string with a \u0000 inside.\u0000" length: 26
qStrL: "A string with a \u0000 inside." length: 25

You're constructing the QString from a const char * literal. The 'embedded' null character will be treated as the terminating null hence the truncation you see under the debugger.

If you want to embed a null you could use something like (untested)...

QString frameDataAsString =
    QString("SEND\n"
            "content-length:23\n\n"
            "Before a Null%1And after").arg('\0');
Related