我的源字符串使用哪种编码

Which encoding are my source strings in?

本文关键字:编码 字符串 我的      更新时间:2023-10-16

当我有这样的C++代码时:

std::string narrow( "This is a narrow source string" );
std::string n2( "Win-1252 (that's the encoding we use for source files): ä,ö,ü,ß,€, ..." );
// What encoding should I pass to Win32's `MultiByteToWideChar` function
// to convert these string to a propoer wchar_t (= UTF-16 on Windows)?

如果这是我们的cpp文件的(隐式)编码,我可以一直假设Win-1252吗?VisualC++编译器如何决定编码源文件的字符?

例如,如果开发人员使用一台"正常"文本文件默认为另一个单字节/多字节编码的机器,会发生什么?

我认为编码只是用于编译代码的机器上的一个问题?也就是说,一旦构建了可执行文件,无论用户PC上的语言/区域设置如何,将静态字符串从固定的窄编码转换为Windows的UTF-16 wchar_t都将始终产生相同的结果?

注意:由于编写了下面的答案,VC++为源代码和执行字符集编码添加了额外的选项。请参见此处。


对于宽字面值,VC++将始终产生UTF-16,而对于窄字面值,VC++将始终从源编码转换为"UTF-16";为非Unicode程序编码";在主机(运行编译器的系统)上设置。因此,只要VC++正确识别源代码,就会得到UTF-16和非Unicode程序的编码。

为了确定源编码,VC++检测所谓的BOM。它将识别UTF-16和UTF-8。如果没有BOM,则假定源代码是使用非Unicode程序的系统编码进行编码的。

如果这导致使用了错误的编码,那么编译器对字符和字符串文字执行的任何转换都将导致ASCII范围之外的任何字符的值错误。


一旦程序被编译,那么是的,只要这些编译时转换进行,区域设置就会停止,因为数据是静态的。

不过,编码可能对其他事情很重要,比如将其中一个字符串打印到控制台。您必须对控制台正在使用的任何内容执行适当的转换,或者确保控制台设置为接受您正在使用的编码。


关于#pragma setlocale的注释

#pragma setlocale只影响到宽文本的转换,它既不通过设置源编码也不通过更改宽执行编码来实现。坦率地说,它的实际作用是可怕的。举个例子,以下断言失败

#pragma setlocale(".1251")
static_assert(L'Я' != L'ß', "wtf...");

如果您对源代码使用任何Unicode编码,则绝对应该避免这种情况。

语言规范只是说源字符是以实现定义的方式映射的。您需要查阅正在使用的编译器的文档,以便了解该实现的定义。例如,Microsoft Visual C++使用#pragma setlocale来指定代码页。