因为我被要求,我会做一些死灵术。其他的答案都是 2009 年的,但这篇文章还是在我 2018 年的一次搜索中出现的。今天的情况非常不同。此外,即使在 2009 年,接受的答案也不完整。
源字符集
每个编译器(包括 Microsoft 的 Visual Studio 2008 及更高版本,gcc、clang 和 icc)都会毫无问题地读取以 BOM 开头的 UTF-8 源文件,而 clang 不会读取除 UTF-8 之外的任何内容,因此 UTF-8带有 BOM 是 C 和 C++ 源文件的最低公分母。
语言标准没有说明编译器需要支持哪些源字符集。一些现实世界的源文件甚至保存在与 ASCII 不兼容的字符集中。 2008 年的 Microsoft Visual C++ 支持带有字节顺序标记的 UTF-8 源文件,以及两种形式的 UTF-16。如果没有字节顺序标记,则假定文件以当前 8 位代码页编码,该代码页始终是 ASCII 的超集。
执行字符集
2012 年,编译器将/utf-8 开关添加到CL.EXE。今天,它还支持/source-charset 和/execution-charset 开关,以及/validate-charset 来检测您的文件是否实际上不是UTF-8。 This page on MSDN has a link to the documentation on Unicode support for every version of Visual C++.
当前版本的 C++ 标准规定编译器必须同时具有一个执行字符集,该字符集确定字符常量的数值,例如 'a',以及一个执行宽字符集,该字符集确定宽字符常量的值,例如L'é'.
对于语言律师来说,标准中关于如何编码的要求很少,但 Visual C 和 C++ 设法打破了它们。它必须包含大约 100 个不能有负值的字符,并且数字 '0' 到 '9' 的编码必须是连续的。大写或小写字母都不必是,因为它们不在一些旧的大型机上。 (也就是说,'0'+9 必须与'9' 相同,但是今天在实际使用中仍有一个编译器,其默认行为是'a'+9 不是'j' 而是'«',这是合法的.) 宽字符执行集必须包括基本执行集并且有足够的位来容纳任何支持的语言环境的所有字符。每个主流编译器都至少支持一种 Unicode 语言环境,并且可以理解使用 \Uxxxxxxxx 指定的有效 Unicode 字符,但没有声称符合标准的编译器。
Visual C 和 C++ 违反语言标准的方式是使它们的 wchar_t UTF-16,它只能将某些字符表示为代理对,而标准规定 wchar_t 必须是固定宽度编码。这是因为微软在 1990 年代将wchar_t 定义为 16 位宽,当时 Unicode 委员会发现 16 位对于整个世界来说都不够用,而且微软也不会破坏 Windows API。它也支持标准的char32_t 类型。
UTF-8 字符串文字
这个问题提出的第三个问题是如何让编译器在内存中将字符串文字编码为 UTF-8。从 C++11 开始,你就可以写出这样的东西了:
constexpr unsigned char hola_utf8[] = u8"¡Hola, mundo!";
无论源字符集是 UTF-8、UTF-16、Latin-1、CP1252 还是 IBM EBCDIC 1047(这是一个愚蠢的理论示例,但为了向后兼容,IBM 的 Z 系列大型机编译器的默认设置)。也就是相当于用{ 0xC2, 0xA1, 'H', /* ... , */ '!', 0 }初始化数组。
如果输入字符太不方便,或者如果您想区分表面上相同的字符,例如空格和不间断空格或预组合和组合字符,您还可以使用通用字符转义:
constexpr unsigned char hola_utf8[] = u8"\u00a1Hola, mundo!";
无论源字符集如何,无论您将文字存储为 UTF-8、UTF-16 还是 UCS-4,您都可以使用这些。它们最初是在 C99 中添加的,但 Microsoft 在 Visual Studio 2015 中支持它们。
编辑: 正如 Matthew 所报告的,u8" 字符串在 MSVC 的某些版本中存在错误,包括 19.14。事实证明,文字非 ASCII 字符也是如此,即使您指定 /utf-8 或 /source-charset:utf-8 /execution-charset:utf-8。上面的示例代码在 19.22.27905 中正常工作。
还有另一种在 Visual C 或 C++ 2008 中有效的方法:八进制和十六进制转义码。您将在该版本的编译器中使用以下代码对 UTF-8 文字进行编码:
const unsigned char hola_utf8[] = "\xC2\xA1Hello, world!";