提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
好的,你上面说的我理解了,现在还有一个问题
这么看来,source-charset正确匹配之后,execution-charset看起来对编码序列的存储更重要,
execution-charset与vs中字符集(使用Unicode字符集/使用多字节字符集)哪个是所谓的设置项目编码,
或者说vs中属性-设置-字符集选择Unicode字符集或者选择多字节字符集对什么有影响,
至少看起来这个设置对源文件中的字符串常量的读取和保存到常量区以及后面存储到变量是没有影响的
另外
QString str2 = QString::fromUtf8("Hello, UTF-8");
这句话我就有点不理解了
QString str2 = QString::fromUtf8(str1);
这样我理解是把str1里面的字节序列按utf-8解码得到码点在按utf-16编码存放到str2中,
但是"Hello, UTF-8"这个过程还是和之前一样吗,
编译器对这个字符串按照source-charset解码,再按execution-charset编码得到字节序列,
再把这个字节序列按照utf-8解码得到码点,再按utf-16编码得到字节序列存放到str2中是吗,
这个过程还是依赖source-charset和execution-charset是吗
你现在的两个问题刚好戳中了“编译期编码规则”和“IDE配置/Qt API”的核心关联点,我先把这两个问题拆解开,用最直白的逻辑讲清楚,帮你彻底理顺。
一、先解答:VS的“字符集设置” vs source/execution-charset
首先明确核心结论:
VS属性里的「使用Unicode字符集」/「使用多字节字符集」和 source-charset/execution-charset 是完全不同维度的设置,前者影响运行时Windows API调用,后者影响编译期字符串字面量的编码转换;所谓“项目编码”,本质是「文件保存编码 + source/execution-charset」,而非VS的字符集下拉框。
1. VS“字符集设置”的本质(不是“项目编码”)
这个设置的核心作用是:给项目定义 UNICODE 或 _MBCS 宏,控制Windows API和TCHAR相关类型的展开,对字符串字面量的编译过程(source/execution-charset)无直接影响。
| VS字符集设置 | 定义的宏 | 核心影响 |
|---|---|---|
| 使用Unicode字符集 | UNICODE+_UNICODE | Windows API的“宽字符版本”生效(如MessageBoxW、CreateWindowW),TCHAR= wchar_t(UTF-16) |
| 使用多字节字符集 | _MBCS | Windows API的“多字节版本”生效(如MessageBoxA、CreateWindowA),TCHAR= char(本地编码) |
举个例子:
// 当VS设为“Unicode字符集”时,_T("测试") 展开为 L"测试"(宽字符,UTF-16)
// 当设为“多字节字符集”时,_T("测试") 展开为 "测试"(单字节,本地编码)
MessageBox(NULL, _T("测试"), _T("标题"), MB_OK);
👉 关键:这个设置不改变编译器处理 "测试" 字面量时的 source/execution-charset 规则,只是改变API调用的参数类型。
2. 什么才是VS里的“项目编码”?
“项目编码”本质是两个层面的统一:
- 文件编码:VS保存.cpp/.h文件时的编码(比如UTF-8 with BOM、GBK);
- 编译器编码选项:即 source-charset 和 execution-charset(VS中可通过「项目属性→C/C++→所有选项→字符集」设置,比如选“UTF-8”会同时把source和execution-charset设为UTF-8)。
只有这两个编码匹配(文件编码=source-charset),才能保证字符串字面量编译时解析不出错;而VS的“Unicode/多字节字符集”只是运行时API的适配,和“项目编码”无关。
3. 补充:VS中如何设置source/execution-charset?
如果你想手动控制这两个charset,在VS中:
- 右键项目→属性→C/C++→所有选项;
- 找到「源字符集」(对应source-charset),设置为文件的实际编码(如UTF-8);
- 找到「执行字符集」(对应execution-charset),推荐设为和source-charset一致(如UTF-8);
- Qt项目还可以在.pro文件中加:
CONFIG += utf8_source(强制编译器用UTF-8处理源码)。
二、再解答:QString::fromUtf8(“Hello, UTF-8”) 的完整执行过程
你的理解方向完全正确,这句话的执行过程确实依赖source-charset和execution-charset,核心是“编译期处理字面量 + 运行时Qt解码”的双层过程,我拆成4步,用“哈”替换部分字符更易理解:
完整步骤(以 QString str = QString::fromUtf8("哈"); 为例)
假设:文件编码=source-charset=UTF-8,execution-charset=GBK(故意设不同,凸显依赖)。
| 阶段 | 具体操作 | 依赖的配置 |
|---|---|---|
| 编译期Step1 | 编译器读取文件中 "哈" 的UTF-8字节(E5 93 88),用source-charset(UTF-8)解码→Unicode码点 U+54C8 | source-charset |
| 编译期Step2 | 编译器用execution-charset(GBK)把码点 U+54C8 编码→GBK字节 B9 FE,存入常量区 | execution-charset |
| 运行时Step3 | fromUtf8 函数接收常量区的 B9 FE 字节序列,尝试按UTF-8规则解码 | Qt的fromUtf8逻辑 |
| 运行时Step4 | 解码结果(失败/成功)→ 转UTF-16存入QString | Qt的UTF-16存储规则 |
关键结果分析:
- 因为execution-charset=GBK,常量区是
B9 FE(GBK字节),而fromUtf8强行按UTF-8解码:
UTF-8规则要求:B9(二进制10111001)是UTF-8的“续字节”(必须跟在首字节后),单独出现属于非法序列 → Qt会把它替换为“替换字符”�(U+FFFD); - 最终str里存的是
�的UTF-16编码,而非“哈” → 乱码!
正确场景(execution-charset=UTF-8):
如果execution-charset也设为UTF-8:
- 编译期Step2后,常量区是
E5 93 88(UTF-8字节); - 运行时Step3,
fromUtf8按UTF-8解码E5 93 88→ 正确码点U+54C8; - Step4转UTF-16存入QString → 正常显示“哈”。
为什么推荐用 QStringLiteral?
QString str = QStringLiteral("哈"); 能跳过上述双层转换:
- 编译期直接把
"哈"转成UTF-16字节序列存入常量区; - 运行时直接复用这个UTF-16序列构造QString,完全不依赖source/execution-charset,既高效又避免乱码。
总结(核心关键点)
- VS的「Unicode/多字节字符集」≠ 项目编码:前者控制Windows API调用,后者由「文件编码 + source/execution-charset」决定;
fromUtf8("字面量")依赖两个charset:execution-charset决定常量区的字节编码,若和fromUtf8的解码规则(UTF-8)不一致,必然乱码;- 最佳实践:
- 统一设置:文件编码=source-charset=execution-charset=UTF-8;
- 硬编码字符串优先用
QStringLiteral,避免双层编码转换的坑; - 只有处理变量字节流(如文件/网络数据)时,才用
fromUtf8/fromLocal8Bit。
1539

被折叠的 条评论
为什么被折叠?



