《从此乱码是路人》笔记
Qt 字符编码专题电子书(约 37 页,Qt 4.x 时代作品,作者为 Qt 社区开发者)。核心主题:彻底搞懂字符编码,让 Qt 程序在任何语言的操作系统上都不乱码。
核心结论(TL;DR)
正确的打开方式:源文件统一保存为 UTF-8,并在 main 里设置两行(不是流传的三行):
QTextCodec::setCodecForTr(QTextCodec::codecForName("utf-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("utf-8"));- 流传的”三行代码”(把 codecForLocale 也设一遍)是错误的:中间那行
setCodecForLocale(codecForLocale())本身无作用;而修改 codecForLocale 要慎重——它决定文件读写的默认编码和 qDebug 输出编码,不该动。 - 这样 tr() 和 const char* → QString 的转换都按 UTF-8 解码,配合 UTF-8 保存源文件,跨语言系统均显示正常。
编码基础知识链
- 计算机只存字节流;字符串 = 字符到字节的映射。
- ASCII:1 字节,英文够用。
- 多字节编码:利用 ≥0x80 字节作前导字节,各国各自制定规则(简体中文第一个国标 GB2312),导致跨国交流困难、混排文章几乎不可能。
- Unicode:统一码联盟 1991 年发布 Unicode 1.0;2001 年 Unicode 3.1 突破 65536 字符,从双字节扩为四字节。
- UCS-2:恒定 2 字节(仅基本多文种平面)
- UTF-16:双字节扩展方案
- UTF-8:1~4 字节变长,兼容 ASCII、避免
\0截断问题,适合传输;中文通常 3 字节 - UTF-32/UCS-4:定长 4 字节
Windows 历史遗留
- WinNT 起内核 API 全部 UTF-16(
CreateWindowW),但保留多字节 API(CreateWindowA)。很多 Windows 程序员不懂编码,程序在中文系统”碰巧正常”,换非中文系统就乱码。
Qt 的编码模型(关键机制)
- QString 内部一律 UTF-16。Qt 从诞生就是国际化项目。
- 源代码中的中文字符串常量,进入 Qt 前经历”多字节编码 → UTF-16”转换:
const char*→ QString 隐式/显式转换:用codecForCStrings指定的编码QObject::tr():用codecForTr指定的编码codecForLocale:当前系统编码(中文 Windows 一般 GBK,中文 Linux 一般 UTF-8)
- Qt 4.x 默认认为源文件是 Latin-1(坏习惯);Qt 5.x 默认 UTF-8。
- 陷阱根源:Qt Creator 保存源文件的编码是 System(= codecForLocale,中文 Windows 即 GBK),于是 GBK 源文件 + codecForLocale=GBK 在中文系统碰巧正常,非中文系统(US-ASCII/SHIFT-JIS 解 GBK)必然乱码。
通用编码转换姿势
QString s = QString::fromUtf8("这是 UTF-8 的字符串");
QByteArray gbk_s = QTextCodec::codecForName("gbk")->fromUnicode(s);
QString s2 = QTextCodec::codecForName("gbk")->toUnicode(gbk_s);文件 IO 默认可用任意编码(默认 codecForLocale):
QFile file(QString::fromUtf8("中文名.txt"));
if (file.open(QIODevice::ReadOnly)) {
QTextStream fin(&file);
fin.setCodec(QTextCodec::codecForName("utf-8"));
fin.readLine();
}文件名含中文也不怕,只要正确转成 QString,剩下的交给 Qt。
tr() 不应滥用
tr("新建文本文档.txt") 这种写法能”顺手”解决乱码,但错误:tr 标记的文本会被 lupdate 扫描出来交给翻译人员,加载翻译文件后替换。文件名不是需要翻译的字符串。乱码问题应该用 fromUtf8 或正确设置 codec 解决,而不是滥用 tr。
可行动点
- 新项目一律 UTF-8 源文件 + UTF-8 执行字符集;维护 Qt 4.8 老项目(如飞凌 i.MX6 平台)时按上面两行 codec 设置自查。
- Qt 5/6 迁移时注意:Qt 5 默认源文件 UTF-8,多数 codec 设置代码可删;Qt 5 移除了
setCodecForCStrings。 - 审查现有代码中的
tr("…文件名/非UI文案…")滥用。
关联
- Qt 学习线:《C++ GUI Qt 4编程》第二版笔记、《Qt样式表武林秘籍》笔记
- 实际应用场景:飞凌 i.MX6 Qt 嵌入式项目(工作线)