如何正确声明 char8_t 变音字母?

How can one properly declare char8_t for diacritical letters?

我尝试使用新的char8_t类型初始化一些变音拉丁字母

constexpr char8_t french_letter_A_1 = 'À';//does not function properly

然而,Visual Studio 2019 提示我以下 “当前代码页无法表示由通用字符名称“\u(名称)”表示的字符”,无法正常显示字符;如果我尝试将字符明确声明为 u8 字符,例如:

constexpr char8_t french_letter_A_2 = u8'Â';//has error

它甚至会抛出错误"一个UTF-8字符文字值不能占用超过一个代码单元";但非变音字母可以成功解释为 UTF-8 之一:

constexpr char8_t french_letter_A_0 = u8'A';//but ASCII letters are fine

我想知道如何使用 Visual C++ 正确声明 UTF-8 字符...或者我误解了 char8_t 的概念,应该使用换别的东西?

编辑:我了解到 char8_t 不支持那些非 ASCII 字符。我应该改用什么字符类型?

UTF-8 是 Unicode 代码点的编码。在 UTF-8 中,一个代码点被分解为一个或多个 "octets"(8 位字),称为 UTF-8 代码单元。表示 UTF-8 代码单元的 C++20 类型是 char8_t.

一个char8_t只是一个UTF-8编码单元。因此,它只能表示一个UTF-8编码只占1个码元的Unicode码位。 Visual Studio 告诉您您试图存储在 char8_t 中的 "character" 需要超过 1 个代码单元,因此不能存储在这种类型中。 UTF-8 在单个代码单元中编码的唯一 Unicode 代码点是 ASCII 代码点。

在处理 UTF-8(或任何非 UTF-32 的 Unicode 编码)时,您不处理 "characters";你处理 strings: 连续的代码单元序列。任何时候你想处理 UTF-8,你应该使用某种基于 char8_t 的字符串类型。

char8_tcharsigned charunsigned char 一样,大小为 1 个字节。在大多数平台上(但不是全部!),这意味着它是一个 8 位类型,只能保存 256 个离散值。 Unicode 12.1 定义了 137,994 个字符。显然,它们不能全部放在一个 char8_t 值中!

令人遗憾的是,C 和 C++ "character" 类型的命名很糟糕。如果我们用现代术语设计一种新语言,我们会将它们命名为 code_unit 的一些变体,因为这样可以更好地反映它们的实际使用方式。 char32_t 是目前唯一保证能够为其关联字符集中的每个字符保留代码点值的字符类型(C 和 C++ 标准声称 wchar_t 也可以,但这与现有做法)。

看看你的例子,À 是 U+00C0 {带有重音的拉丁文大写字母 A}(或者实际上是 A U+0041 {拉丁文大写字母 A} 后跟 ̀ U+0300 {组合重音符}? Unicode 这样很棘手)。 U+00C0的UTF-8编码为0xC3 0x80。 french_letter_A_1 应该保持什么值?它不能包含两个代码单元值。如果该值是代码点,那么我们要么处于只能(可移植)支持 256 个字符的情况,要么更糟的是,有时 char8_t 的值是代码点,有时它们是代码单位。

实际情况是 C 和 C++ 字符文字仅限于比 basic source character set 中多几个字符。如果一个人正在编写一个只有英文的应用程序,这就足够了。但是对于现代应用程序,字符文字的用途有限。

正如 Nicol 已经指出的那样,使用基本源字符集之外的大多数字符需要对字符串进行真正的文本处理。不幸的是,C 和 C++ 标准在这方面没有提供太多帮助。这是 SG16 正在努力改进的地方。