33

来自维基百科

为了增强 C++ 编译器中对 Unicode 的支持,已将 char 类型的定义修改为至少存储 UTF-8 的八位编码所需的大小。

我想知道这对于编写可移植应用程序到底意味着什么。写这个有什么区别吗

const char[] str = "Test String";

或这个?

const char[] str = u8"Test String";

是否有任何理由不对代码中的每个字符串文字使用后者?

当 TestString 中有非 ASCII 字符时会发生什么?

4

4 回答 4

31

的编码"Test String"是实现定义的系统编码(窄的,可能是多字节的)。

的编码u8"Test String"始终为 UTF-8。

这些例子并不是很能说明问题。如果您在字符串中包含一些 Unicode 文字(例如\U0010FFFF),那么您总是会得到那些(编码为 UTF-8),但它们是否可以在系统编码的字符串中表示,如果是,它们的值是什么,是实现定义的。

如果有帮助,想象一下您正在 EBCDIC 机器上创作源代码。然后文字“测试字符串”总是在源文件本身中进行 EBCDIC 编码,但u8-initialized 数组包含 UTF-8 编码值,而第一个数组包含 EBCDIC 编码值。

于 2012-11-18T21:48:42.957 回答
16

你引用维基百科:

为了在 C++ 编译器中增强对 Unicode 的支持,已将 char 类型的定义修改为至少存储 UTF-8 的八位编码所需的大小。

好吧,“为了目的”是不正确的。由于C 标准中要求的范围char,始终保证至少为 8 位,即CHAR_BIT始终要求≥8 。char这是(引用 C++11 §17.5.1.5/1)“合并”到 C++ 标准中。

如果我应该猜测措辞更改的目的,那将只是为那些不知道对 C 标准的依赖的读者澄清一些事情。

关于u8字面前缀的效果,它

  • 影响可执行文件中字符串的编码,但

  • 不幸的是,它不会影响类型。

因此,在这两种情况下"tørrfisk"u8"tørrfisk"您都会得到一个. 但是在前一种文字中,编码是为编译器选择的任何内容,例如,对于拉丁语 1(或 Windows ANSI Western),对于数组大小为 9,字符为 8 个字节加上一个空字节。而在后一种文字中,编码是保证为 UTF-8,其中“ø”将被编码为 2 或 3 个字节(我不记得确切),用于稍大的数组大小。char const[n]

于 2012-11-18T22:13:40.117 回答
9

如果编译器的执行字符集设置为 UTF-8,则u8使用与否没有区别,因为编译器在两种情况下都将字符转换为 UTF-8。

但是,如果编译器执行字符集是系统的非 UTF8 代码页(例如 Visual C++ 的默认值),则u8省略时可能无法正确处理非 ASCII 字符。例如,转换为宽字符串会崩溃,例如在 VS15 中:

std::string narrowJapanese("スタークラフト");
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convertWindows;
std::wstring wide = convertWindows.from_bytes(narrowJapanese); // Unhandled C++ exception in xlocbuf.
于 2017-05-02T14:08:49.250 回答
8

编译器选择平台自然的本机编码。在典型的 POSIX 系统上,它可能会选择 ASCII 并且可能取决于环境对 ASCII 范围之外的字符值的设置。在大型机上,它可能会选择 EBCDIC。比较从文件或命令行接收的字符串可能最适合使用本机字符集。但是,在处理使用 UTF-8 显式编码的文件时,最好使用u8"..."字符串。

也就是说,随着最近与字符编码相关的变化,C 和 C++ 中字符串处理的基本假设被打破:每个内部字符对象(charwchar_t等)用于表示一个字符。对于每个字符对象仅代表某个字符的一个字节的 UTF-8 字符串,这显然不再适用。因此,所有字符串操作、字符分类等功能不一定适用于这些字符串。我们没有任何好的库来处理这些字符串以包含在标准中。

于 2012-11-18T22:04:15.167 回答