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

How can one properly declare char8_t for diacritical letters?

本文关键字:char8 何正确 声明      更新时间:2023-10-16

我尝试使用新的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

我想知道如何使用视觉C++正确声明 UTF-8 字符......或者我误解了char8_t的概念,应该使用其他东西来代替?

编辑:我已经理解char8_t不支持那些非ASCII字符。我应该改用哪种字符类型?

char8_t,像charsigned charunsigned char一样,大小为1字节。 在大多数平台上(但不是全部!(,这意味着它是 8 位类型,只能容纳 256 个离散值。 Unicode 12.1 定义了 137,994 个字符。 显然,它们不可能都符合一个单一的char8_t值!

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

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

现实情况是,C 和 C++ 字符文本仅限于比基本源字符集中多几个字符。 如果一个人正在编写一个纯英语的应用程序,这就足够了。 但对于现代应用程序,字符文本的用途有限。

正如 Nicol 已经说过的,处理基本源字符集之外的大多数字符需要对字符串进行真正的文本处理。 不幸的是,C 和 C++ 标准在那里没有提供太多帮助。 这是第16研究组正在努力改进的。

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

单个char8_t只是一个 UTF-8 代码单元。因此,它只能表示 Unicode 代码点,其 UTF-8 编码仅占用 1 个代码单元。Visual Studio告诉您,您尝试存储在char8_t中的"字符"需要1个以上的代码单元,因此不能以这种类型存储。UTF-8 在单个代码单元中编码的唯一 Unicode 码位是 ASCII 码位。

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