以L开头的宽字符字符串字面值(如 L"Hello World")是否保证采用Unicode编码?

17

我最近尝试了解创建跨平台支持Unicode的C++应用程序所需的步骤。让我感到困惑的是,大多数教程都把字符编码(即ANSI或Unicode)和字符类型(char或wchar_t)等同起来。据我所知,这些是不同的东西,可能存在一种由Unicode编码但由std::string表示的字符序列,以及一种由ANSI编码但由std::wstring表示的字符序列,对吗?

那么,我想知道的问题是,C++标准是否保证以L开头的字符串文字的编码?还是只说它是wchar_t类型,并具有实现特定的字符编码?

如果没有这样的保证,这是否意味着我需要某种外部资源系统以平台无关的方式提供非ASCII字符串文字给我的应用程序?哪种方法更好?资源系统还是正确编码源文件加上适当的编译器选项?


"在Unicode中没有所谓的“编码”。如果你指的是widechar或UTF-16,那么我建议你重新考虑首选编码,并使用UTF-8代替。请参见http://stackoverflow.com/questions/1049947/should-utf-16-be-considered-harmful/1855375#1855375" - Pavel Radzivilovsky
3个回答

43

L符号放在字符串字面值前,意味着该字符串中的每个字符都将被存储为wchar_t类型。但这并不一定意味着Unicode。例如,你可以使用宽字符字符串来编码GB 18030,这是中国使用的类似于Unicode的字符集。C++03标准对Unicode没有任何规定(然而C++11定义了Unicode char类型和字符串字面值),因此在C++03中正确表示Unicode字符串就靠你自己了。

关于字符串字面值,C++标准的第2章(词法约定)提到了一个“基本源字符集”,基本上等同于ASCII。所以这基本保证了"abc"将被表示为一个3字节的字符串(不计算空字符),而L"abc"将被表示为一个由宽字符组成的3 * sizeof(wchar_t)字节的字符串。

标准还提到了“通用字符名”,允许您使用\uXXXX十六进制记法引用非ASCII字符。这些“通用字符名”通常直接映射到Unicode值,但标准并不保证必须这样。但是,使用通用字符名,您至少可以保证字符串将表示为特定的字节序列。这将确保Unicode输出(前提是运行时环境支持Unicode、安装了适当的字体等)。

至于C++03源文件中的字符串字面值,同样没有保证。如果您的代码中有一个包含ASCII范围之外字符的Unicode字符串字面值,则编译器将决定如何解释这些字符。如果你想明确保证编译器会“做正确的事情”,你需要在你的字符串字面值中使用\uXXXX记法。


3
回答不错而且详尽。或许值得补充一些关于一些特定(但受欢迎的)平台保证Unicode的信息,例如我所知道的所有Windows实现以及GNU libc都能够保证Unicode。另一方面,FreeBSD不能保证,并且有一些地区设置下宽字符串不是Unicode编码。此外,C99增加了一个预处理器符号,如果某个实现的所有字符串函数无论所在位置如何都将宽字符串作为Unicode进行处理,则该符号可以定义 - __STDC_ISO10646__,例如GNU libc定义了该符号。不幸的是,即使符合语义,MSVC也没有定义该符号。 - Pavel Minaev
1
另外,\u确实保证了映射到Unicode - 像\u1234这样的东西始终是由Unicode代码点1234表示的字符,只要执行宽字符集支持它。然而,即使字符被支持,也没有要求L'\u1234' == 1234,因为该字符可能会被重新映射。有关详细信息,请参见ISO C++ 2.2 [lex.charset] / 2。 - Pavel Minaev
除了Pavel的评论之外:macOS也是基于UTF-16(UCS-2)构建的。 - Martin York

3

C++03标准中未提到Unicode(C++0x标准中有所涉及)。目前,您需要使用外部库(如ICUUTF-CPP等)或使用平台特定代码构建自己的解决方案。正如其他人所提到的,wchar_t编码(甚至大小)未经规定。因此,字符串文字的编码是实现特定的。但是,您可以使用\x \u \U转义在字符串文字中给出Unicode代码点。

通常,Windows中的Unicode应用程序使用wchar_t(采用UTF-16编码)作为内部字符格式,因为它使得使用Windows API更加容易,而Windows本身使用UTF-16。相反,Unix/Linux Unicode应用程序通常在内部使用char(采用UTF-8编码)。如果要在不同平台之间交换数据,则UTF-8是数据传输编码的通常选择。


1
C++03提到了ISO10646,它是ISO的Unicode等效标准,由于C++是ISO标准,因此它们引用其他ISO标准而不是Unicode。在实践中,没有区别(例如,相同字符具有相同的值)。 - MSalters
1
是的,这就是为什么可以通过 \u \U 转义来给出代码点。然而,ISO10646(UCS)与Unicode不同 - (Unicode)“对实现施加了额外的约束”,并且“提供了广泛的功能字符规范、字符数据、算法和大量背景材料,这些都不在ISO/IEC 10646中”。 - eidolon

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接