C++11中字符串字面量的Unicode编码

91

有关问题的基础上,我想询问C++11中的新字符和字符串字面值类型。现在似乎有四种字符类型和五种字符串字面值类型。

char     a =  '\x30';         // character, no semantics
wchar_t  b = L'\xFFEF';       // wide character, no semantics
char16_t c = u'\u00F6';       // 16-bit, assumed UTF16?
char32_t d = U'\U0010FFFF';   // 32-bit, assumed UCS-4

以及字符串文字:

char     A[] =  "Hello\x0A";         // byte string, "narrow encoding"
wchar_t  B[] = L"Hell\xF6\x0A";      // wide string, impl-def'd encoding
char16_t C[] = u"Hell\u00F6";        // (1)
char32_t D[] = U"Hell\U000000F6\U0010FFFF"; // (2)
auto     E[] = u8"\u00F6\U0010FFFF"; // (3)
问题是:在所有字符串类型中,\x/\u/\U字符引用是否可以自由组合?所有的字符串类型都是固定宽度的,也就是说数组包含的元素数量与字面量中出现的精确相同,还是\x/\u/\U引用会扩展为可变数量的字节?u""u8""字符串是否具有编码语义,例如我可以这样写char16_t x[] = u"\U0010FFFF",而非BMP代码点将被编码成两个单元的UTF16序列?对于u8也是如此吗?在(1)中,我能否使用\u写下孤立的代理项?最后,任何字符串函数是否具有编码意识(即它们是字符感知的,并且可以检测到无效的字节序列)?
这是一个开放式的问题,但我希望尽可能全面地了解新C++11的UTF编码和类型工具。

4
GCC将u"\U0010FFFF"编码为代理对。 - kennytm
1个回答

62
在任何字符串类型中,都可以使用 \x,但只能在特定的UTF编码字符串中使用 \u\U。但对于任何UTF编码字符串,\u\U 可以随意使用。 \x\u\U 的转换是基于字符串编码的。这些 "代码单元"(使用Unicode术语。一个 char16_t 是一个UTF-16代码单元)值的数量取决于包含字符串的编码。字面量 u8"\u1024" 会创建一个包含2个 char 加上一个空终止符的字符串。而字面量 u"\u1024" 则会创建一个包含1个 char16_t 加上一个空终止符的字符串。 u"" 创建一个UTF-16编码的字符串。u8"" 创建一个UTF-8编码的字符串。它们将按照Unicode规范进行编码。
在 (1) 中,我可以使用 \u 写单独的代理项吗?

绝对不能。规范明确禁止使用UTF-16代理对(0xD800-0xDFFF)作为\u\U的代码点。

最后,任何字符串函数是否具有编码意识(即它们是基于字符的,并且可以检测到无效的字节序列)?

绝对不行。好吧,让我重新说一遍。

std::basic_string不处理Unicode编码。它们当然可以存储UTF编码的字符串。但是,它们只能将它们视为charchar16_tchar32_t序列;它们不能将它们视为以特定机制编码的Unicode代码点序列。basic_string::length()将返回代码单元的数量,而不是代码点的数量。显然,C标准库字符串函数是完全没有用的。

然而,需要注意的是,Unicode字符串的“长度”并不意味着代码点的数量。一些代码点是组合“字符”(一个不幸的名称),它们与前面的代码点组合在一起。所以多个代码点可以映射到单个可视字符。

Iostreams实际上可以读写Unicode编码的值。要这样做,您将需要使用区域设置来指定编码,并在各个地方正确地注入它。这比说起来容易得多,我手头没有任何代码可以向您展示如何操作。


7
@Philipp:不,它们不是。Unicode专门为UTF-16代理保留了它们。正如所述,C++0x的规范说明,如果您尝试指定该范围内的代码点,则编译将失败。 - Nicol Bolas
13
您的链接证明它们确实是码点。如果您不信任维基百科,请阅读标准第3章中定义9和10。但在C++0x中,字符串文字中的代理码点是被规则§ 2.4/2禁止的。 - Philipp
1
阅读后,我也确认代理码点在字符串字面量中是被接受的。 - George Kourtis
在C11中,\x不能与任何东西一起使用,例如U+1F984将无法与\x前缀一起使用,而且\u\U不能与ASCII控制字符一起使用,至少在Clang中是如此。 - MarcusJ

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