为什么在未实例化QCoreApplication时,QString不能正确处理特殊字符?

8

我开始在Qt中编写一个非常基本的文本操作应用程序,没有GUI界面。我的文本包含特殊字符,但无论我做什么都无法打印出这些特殊字符。

后来我注意到,在添加了一个QCoreApplication实例之后(我之前删除了它,因为我认为我不需要它),一切都像应该的那样正常工作了。

以下是代码:

#include <QCoreApplication>
#include <QString>
#include <QDebug>

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

    QString s(QString::fromUtf8("aä\xc3\xa4")); // aää

    qDebug() << s;
    qDebug() << s.toAscii();
    qDebug() << s.toLatin1();
    qDebug() << s.toUtf8();
    qDebug() << s.toLocal8Bit();
    qDebug("%s", qPrintable(s));

    qDebug("%i", s.length());
    qDebug("%i", strlen(qPrintable(s)));

    return 0;
}

使用 QCoreApplication 进行输出(一切正常):

"aää" 
"aää" 
"aää" 
"aää" 
"aää" 
aää
3
5

在注释掉定义 QCoreApplication 的行后,输出结果如下(不再显示特殊字符):

"a" 
"a" 
"a" 
"a" 
"a" 
a
3
1

请注意,即使在调用qPrintabable(s)后,特殊字符也已被删除。我进行了测试以确保QDebug不是问题所在。
我还检查了文件是否真的以UTF-8编码。
当没有实例化QCoreApplication时,为什么QString不能正确处理特殊字符?

非常有趣的问题...我猜原因可能在 QTextCodecQTextStream 之中,但我也可能错了。QDebug 使用一个 QTextStream,但正如你所观察到的,qPrintable(它只是 .toLocal8Bit().constData() 的简写形式)已经神奇地删除了你的非 ASCII 字符或插入了一个 '\0',因为这是 strlen 应该返回1的唯一解释。 - leemes
插入 '\0' 不是问题,因为我已经测试了其他字符串,如 "aäa",其中特殊字符后面跟着其他字母。它们不会被删除。换句话说,如果 s"aäa",则在不使用 QCoreApplication 的情况下输出为 "aa" - Misch
1个回答

8

在查看Qt源代码时,我偶然发现了一个在构造QCoreApplication时调用的代码:

#ifdef Q_OS_UNIX
    setlocale(LC_ALL, "");                // use correct char set mapping
    qt_locale_initialized = true;
#endif

换句话说,在“Unix”系统上,“QCoreApplication”构造函数调用“locale.h”中的“setlocale”函数来设置程序的当前区域设置。这最终会影响到“qDebug”的输出,它依赖于“QTextStream”,后者最终使用它认为是系统定义的区域设置来创建其输出。
当我在Linux系统上测试您的代码时,遇到了与您相同的结果。在Windows系统上,注释掉“QCoreApplication”构造对结果没有影响。我还注意到,无论是否构造“QCoreApplication”,通过“printf”打印原始字符串都会给出正确的结果。

这是一个bug还是Qt规定在使用其他Qt组件或类之前必须初始化Q(Core)Application - Misch
@Misch Qt指定了必须初始化Q(Core)Application的条件。请参考http://qt-project.org/doc/qt-4.8/qcoreapplication.html。这种特定行为在“Locale Settings”部分有详细说明。 - RA.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接