qt 汉字输出 中文输出 显示乱码 qDebug() 乱码 解决
要正确显示汉字,必须要先了解计算机文字编码相关知识,参考:
unicode ucs2 utf16 utf8 ansi GBK GB2312 互转 及 渲染_ucs2编码转换-CSDN博客
qt vs 编程 字符编码 程序从源码到编译到显示过程中存在的字符编码及隐藏的字符编码转换 中文输出 乱码 原因-CSDN博客
1、汉字输出到 应用程序输出面板
qt 自定义的输出类qDebug() 、QDebug对象、QMessageLogger默认输出到 应用程序输出面板 。
这些输出工具类对象会将所有的字符串转变为QString类型,然后内部代码会利用Windows.h中OutputDebugStringW(wchar_t*) 输出到面板上。当使用vs编译器时,你也可以直接调用这个windows API输出到面板上。
我们都知道QString类型中将字符串全部按unicode的utf16编码,每个字符都有两个字节保存。正常来将,存放字符串到QString中时指定正确的编码,就能正确的显示字符串。
#include <QDebug>
#include <Windows.h>int main()
{QString str1 = QString::fromWCharArray(L"你好"); // 字符串前加L,强制将字符串保存为unicode utf16编码保存到内存中QString str2 = QString::fromUtf8(u8"你好"); //字符串前加u8,强制将字符串保存为unicode utf8编码保存到内存中。qDebug()<<"str1:"<<str1<<endl<<"str2:"<<str2<<endl;OutputDebugString(L"你好");return 0;
}
如果不加前缀,就需要你对文件字符编码和编译器默认字符编码及要求有所了解, 可以参考这个:程序从源码到编译到显示过程中存在的字符编码及隐藏的字符编码转换
但有个意外:当qt使用mingw编译器时,输出到应用程序输出面板上时,给OutputDebugStringW()投喂unicode的utf-16编码(双字节)的字符串,会被莫名其妙的按单个字节拆成unicode的utf16编码,暂时还没找到什么原因(可以确定这不是qt的问题,而是编译器的对接windowsAPI的问题)。比如"你好" ,utf16为0x4F60 0x597D,虽然内存中存放的还是正确的utf16编码,但是在选用Mingw编译器输出到output panel时显示成ÄãºÃ,对应的utf16编码为:0x00C4 0x00E3 0x00BA 0x00C3
这样Mingw就不能正确将汉字输出到 应用程序输出面板 中。就需要选择输出到控制台窗口
下面是两个可以直接显示到output panel 的windows api。加上<windows.h>就可以直接调用
OutputDebugStringW(L"aaa你好"); //windows api,用于将utf16编码的字符串显示到output panel上OutputDebugStringA("aaa你好"); //windows api,用于将ansi编码的字符串显示到output panel上
2、汉字输出到控制台窗口
qt自定义输出类QDebug类、qDebug()、QMessageLogger类、qt_message_output() 默认输出到到qt ide 的 应用程序输出面板 (application output panel)上,需要通过设置来输出到 控制台窗口
vs qt 调试 输出 打印 到 输出窗口 或 控制台窗口_qt输出信息到窗口-CSDN博客
控制台窗口显示正确的汉字需要很小心。
1、最基础的是要明确知道你投喂给控制台窗口的字符串是什么编码的。QString中字符串是以unicode的utf16编码进行保存的。当需要输出到控制台的时候,内部会通过QTextCodec进行转码,转成QTextCodec所设置的目标编码的字符串。然后再输出给控制台。
2、控制台只支持显示 兼容ascii编码 的编码方式,可以是ansi(GB2312),可以是utf8,但是不支持显示utf16编码。
控制台所支持的字体库有限,并且只能是GB2312字符集,对于超出的显示会乱码或两问号。具体原因比较复杂。
通过system("chcp 65001"); 设置控制台显示utf8编码的字符,通过system("chcp 936"),设置控制台显示GB2312编码的字符。
3、其次投喂给控制台的字符编码需要与控制台当前支持的编码要一致。在字符串前面加u8 ,强制字符串以utf8编码的方式存入到char*类型变量的内存中。这个无法强制QString,任何编码类型的字符串输入给QString保存,QString都会自动转码成utf16编码。如果需要可以使用QByteArray 或者QLatin1String进行保存。详细请参考:QString 与 字符编码 QTextCodec-CSDN博客
4、QString或者 QTextCodec 提供了非常方便使用的文字编码转换接口。
另外QString向控制台输出的时候有一个toLocal8Bit()的过程。这是导致在控制台显示乱码的一个因素。如果使用qt自定义输出类及接口向控制台窗口输出,想要正确输出汉字,必须要指定正确的QTextCodec。QTextCodec默认为system,windows下为ansi,linux下为utf8。
D:\Qt\Qt5.12.0\5.12.0\Src\qtbase\src\corelib\global\qlogging.cpp
......
static void stderr_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
{QString formattedMessage = qFormatLogMessage(type, context, message);// print nothing if message pattern didn't apply / was empty.// (still print empty lines, e.g. because message itself was empty)if (formattedMessage.isNull())return;fprintf(stderr, "%s\n", formattedMessage.toLocal8Bit().constData());fflush(stderr);
}
......D:\Qt\Qt5.12.0\5.12.0\Src\qtbase\src\corelib\tools\qstring.cpp
......
QByteArray QStringRef::toLocal8Bit() const
{return qt_convert_to_local_8bit(*this);
}
.....
static QByteArray qt_convert_to_local_8bit(QStringView string)
{if (string.isNull())return QByteArray();
#ifndef QT_NO_TEXTCODECQTextCodec *localeCodec = QTextCodec::codecForLocale();if (localeCodec)return localeCodec->fromUnicode(string);
#endif // QT_NO_TEXTCODECreturn qt_convert_to_latin1(string); //被当做ascii编码处理。
}
......
案例
#include <QTextCodec>
#include <QDebug>
#include <Windows.h>
int main()
{//QTextCodec编码器要与编译器参数execution-charset(vs编译器,默认为GB2312)/fexec-charset(gcc或类gcc编译器,默认为UTF8)的值一致,QTextCodec *codec=QTextCodec::codecForName("GB2312"); //设置QString的fromLocal8Bit() 和toLocal8Bit()的QTextCodec为GB2312QTextCodec//QTextCodec *codec=QTextCodec::codecForName("UTF-8"); //设置QString的fromLocal8Bit() 和toLocal8Bit()的QTextCodec为UTF-8 QTextCodecQTextCodec::setCodecForLocale(codec);QString s=QString::fromLocal8Bit("你好");//QString s=QString::fromUtf8(u8"你好"); //system("chcp 936"); //设置控制台输出窗口接收GB2312编码的字符串//system("chcp 65001"); //设置控制台输出窗口接收utf8编码的字符串qDebug()<<s<<endl;return 0;
}
3、编译器坑
vs2015编译器,需要更新 Visual Studio 2015 Update 2,才能支持下面两个选项。
下面两个参数告知编译器输入源文件编码 及 告诉编译器编译程序时将字符串保存到内存中使用的字符编码(使用u8和L前缀字符串除外),这样通过变量访问或者调试查看内存,会发现获取到的字符编码就是execution-charset所指定的字符编码。
//gcc 或 类gcc编译器
QMAKE_CXXFLAGS += -finput-charset=UTF-8
QMAKE_CXXFLAGS += -fexec-charset=UTF-8
//vs编译器
QMAKE_CXXFLAGS += /source-charset:utf-8
QMAKE_CXXFLAGS += /execution-charset:utf-8
上面的参数不能混用
//测试代码
#include <QDebug>
#include <QTextCodec>
#include <iostream>
using namespace std;int main(int argc, char *argv[])
{QTextCodec *codec = QTextCodec::codecForName("UTF-8"); //QTextCodec::setCodecForLocale(codec);//cout<<::getenv("path")<<endl;system("chcp 65001");cout<<u8"你好𬌗"<<endl;qDebug()<<"aa你好𬌗"<<endl;return 1;
}
测试结果
QString 与 字符编码 QTextCodec-CSDN博客
qt 日志输出 QMessageLogger QDebug QLoggingCategory qDebug qt_message_output() qInstallMessageHandler()-CSDN博客