2
votes

I try to avoid mixed QString and char* types in a QT program. I have a conversation function that returns a pointer of the data inside the QString, but I get very strange results. Whats wrong with this code?

Compiler and environment gcc (Debian 4.9.2-10) 4.9.2 Flags via qmake: QMAKE_CXXFLAGS += -std=c++11

Code snippet:

#include <QCoreApplication>
#include <iostream>
#define  PCH(m) ( m.toAscii().data() )

// get the pointer short scripted
const char* CH(QString msg) {
   const char* res = msg.toAscii().data();
   return res;
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    const QString qformat = "%s does not work!";
    const QString qvalue  = "embedding";

    // Works not
    qDebug(CH(qformat), CH(qvalue));   

    // Works
    qDebug(qformat.toAscii().data(), qvalue.toAscii().data());

    // Works too but macro
    qDebug(PCH(qformat), PCH(qvalue));   

    return app.exec();
}

Results

%s does not work! does not work!

embedding does not work!

embedding does not work!
2

2 Answers

2
votes

Here you are copying QString to function, and return pointer to already destroyed data inside function. This is known undefined behavior, since you are returning pointer to garbage. Return QString.

const char* CH(QString msg) {
    const char* res = msg.toAscii().data();
    return res;
}
2
votes

You should be using qDebug() and the formatting mechanism built into QString itself. You should also use QStringLiteral instead of depending on default string conversions - after all you've stated that you care about such things:

#include <QtCore>
int main()
{
    const auto qformat = QStringLiteral("%1 does work!");
    const auto qvalue = QStringLiteral("embedding");
    qDebug() << qformat.arg(qvalue);
    qDebug() << qformat.arg(0x7A01173C2, 0, 16);
}

The QStringLiteral, used on modern compilers, does not create an 8-bit C-string. It assembles a binary internal representation of a QString at compile time, and stores it in a read-only memory section of your executable. This is the only way to avoid runtime costs of string encoding.

There is no benefit whatsoever in doing a roundtrip via QString if you already have UTF8 encoded string literals or C-style strings that are UTF8 encoded. If you need to use C-style strings/string literals, use them directly with qDebug:

#include <QtCore>
int main() {
    const char format[] = "%s does not work!";
    const char value[] = "embedding";
    qDebug(format, value);
}

If you need to pass temporary C-style strings, use QByteArray, but that's really a lot of code with very little to show for it - it's so verbose as to have a very bad code smell. So don't do it like this:

#include <QtCore>
QByteArray CH(const QString &msg) {
   return msg.toLocal8Bit();
}

int main()
{
    auto qformat = QStringLiteral("%s does work!");
    auto qvalue = QStringLiteral("embedding");
    qDebug(CH(qformat).constData(), CH(qvalue).constData());
}