C++23:char 现在支持 Unicode?

mis*_*har 19 c++ unicode char literals character-encoding

C++23 现在是否在其基本类型中提供对 Unicode 字符的支持char,支持程度如何?


因此,在字符文字的 cppreference上,字符文字:

'c-char'
Run Code Online (Sandbox Code Playgroud)

定义为:

  • Abasic-c-char
  • 转义序列,如转义序列中所定义
  • 通用字符名称,如转义序列中定义

然后对于basic-c-char,定义为:

来自基本源字符集 (C++23 之前) 翻译字符集 (C++23 起) 的字符,但单引号'、反斜杠\或换行符除外

在cppreference 的字符集页面上,它将“翻译字符集”定义为由以下内容组成:

  • 每个抽象字符在 Unicode 代码空间中分配一个代码点,并且(C++23 起)
  • 每个 Unicode 标量值的不同字符未分配给抽象字符。

并指出:

翻译字符集是基本字符集和基本文字字符集的超集(见下文)。

在我看来,“基本字符集”(在上一页给出)基本上是 ASCII 的子集。我也一直认为char是 ASCII(支持 ISO-8859 字符集,例如Microsoft 的字符类型页面)。但现在随着 翻译字符集的改变basic-c-char,它似乎在某种程度上支持了 Unicode。

我知道实际的编码是实现定义的(除了空字符和递增的十进制数字字符之外)。但我的主要问题是这个“翻译字符集”真正支持哪些字符?都是Unicode吗?我觉得我对这件事的解读比实际情况要多。

use*_*522 17

实际上没有太大变化(有两个重要的区别):

在 C++23 之前,第一个翻译阶段定义源文件中不是基本源字符集(ASCII 字符集的子集)元素的任何字符都将映射到通用字符 - name,即它将被替换为以下形式的序列\UXXXXXXXX,其中XXXXXXXX是字符的 ISO/IEC 10646(等效于 Unicode)代码点的编号。

然后,当编写字符文字时'X',其中X替换为基本源字符集中不存在的字符,您将'\UXXXXXXXX'在第一个翻译阶段之后得到,然后应用c-char -> 通用字符名称语法。

因此,假设源编码允许写入此类字符,您始终可以在字符文字中写入非 ASCII 字符。源文件编码和基本源字符集之外支持的源字符被实现定义为源字符集(编码)。无论源字符集如何,您都可以将任何 Unicode 标量值直接写入具有通用字符名称的字符文字中。

这个字符文字将如何表现是一个不同的问题,因为用于确定char通用字符名称(或基本源字符集的任何字符)的值的编码也是实现定义的(执行C++20 中的字符集编码或C++23 中的普通文字编码)。显然,如果char是 8 位宽,它不能表示所有 Unicode 标量值。如果该字符无法在 中表示char,则该行为是实现定义的。

C++23 的更改现在是强制支持 UTF-8 源编码,这意味着支持源文件中的所有 Unicode 标量值(当然也可以支持其他编码)并且第一阶段已更改,这样一来,不再通过通用字符名称将所有内容重写为基本源字符集,而是将源字符映射到本质上是 Unicode 标量值序列的翻译字符集序列。不是 Unicode 标量值的 Unicode 代码点(即代理代码点)不是翻译字符集的元素(并且不能通过解码任何源文件来生成)。

因此,在 C++23 中,当进入确定字符文字值的翻译阶段时,源文件中的单个 Unicode 标量值与您在问题中所示的basic-c-char语法相匹配。

字符文字的值仍然像以前一样由实现定义的编码确定。然而,与 C++20 相比,如果字符无法char通过此编码表示,则文字现在是格式错误的。

因此,两个区别是必须支持 UTF-8 源文件编码,并且字符文字中的单个源字符(表示单个 Unicode 标量值)在实现定义的普通文字编码中无法表示,现在将导致文字格式不正确,而不是具有实现定义的值。


与上面类似,字符串文字(而不是字符文字)也没有真正改变。编码仍然是使用相同的普通文字编码来实现定义的,并且主要只是翻译阶段中的内部表示发生了变化。与字符文字相同,对于 C++23,如果字符(即翻译字符集元素或 Unicode 标量值)无法用普通文字字符编码表示,则文字将变得格式错误。然而,该编码可以是例如UTF-8,使得源文件中的单个Unicode标量值可以映射到char编码字符串中的多个,就像一直以来的情况一样。


eer*_*ika 5

\n

这个“翻译字符集”真正支持哪些字符?

\n
\n

正如您已经引用的那样(我将引用最新的 C++ 标准草案):

\n
\n

[lex.charset]

\n

翻译字符集由以下元素组成:

\n
    \n
  • 每个抽象字符在 Unicode 代码空间中分配一个代码点,并且
  • \n
  • 每个 Unicode 标量值的不同字符未分配给抽象字符。
  • \n
\n
\n

让我们查找一下规则中使用的术语的定义(引自 Unicode 14):

\n

对于第一点:

\n
\n

字符和编码

\n

抽象字符:用于组织、控制或表示文本数据的信息单位。

\n
    \n
  • 表示数据时,该数据的性质通常是象征性的,而不是其他类型的数据(例如听觉或视觉)。此类符号数据的示例包括字母、表意文字、数字、标点符号、技术符号和标志。
  • \n
  • 抽象字符没有具体的形式,不应与字形混淆。
  • \n
  • 抽象字符不一定对应于用户所认为的 \xe2\x80\x9ccharacter\xe2\x80\x9d,并且不应与字素混淆。
  • \n
  • 由 Unicode 标准编码的抽象字符称为 Unicode 抽象字符。
  • \n
  • 不直接由 Unicode 标准编码的抽象字符通常可以通过使用组合字符序列来表示
  • \n
\n
\n

对于第二点:

\n
\n

Unicode 编码形式

\n

Unicode 标量值:除高代理项和低代理项代码点之外的任何 Unicode 代码点。

\n
    \n
  • 由于此定义,Unicode 标量值集由范围 0 到 D7FF 16 和 E000 16 到 10FFFF 16(含)组成。
  • \n
\n
\n

C++ 标准也有一个澄清说明:

\n
\n

[注 1:\xe2\x80\x82Unicode 代码点是 [0, 10FFFF]\n(十六进制)范围内的整数。代理代码点是 [D800,\nDFFF](十六进制)范围内的值。Unicode 标量值是不是代理代码点的任何代码点。\xe2\x80\x94 尾注]

\n
\n
\n
\n

都是Unicode吗?

\n
\n

TLDR:不。例如。代理代码点和组合字符序列不在翻译字符集中。

\n

此外,这是 C++ 的重要规则:

\n
\n

具有由单个 basic-c-char、simple-escape-sequence 或 universal-character-name 组成的 c-char-sequence 的字符文字是在该文字的关联字符编码中编码的指定字符的代码单元值.\n如果指定的字符缺乏文字关联字符编码的表示,或者无法将其编码为单个代码单元,则该程序格式错误。

\n
\n

如果您的系统是 8 位char,那么它将无法表示 Unicode 代码空间的所有 10FFFF 代码点。

\n
\n

PS 中的 Unicodechar从未被 C++ 标准禁止;此更改只是强制强制支持 Unicode。

\n

  • “如果你的系统有一个 8 位 char,那么它将无法表示 Unicode 代码空间的所有 10FFFF 代码点” 单个 8 位 `char` 文字今天显然无法做到这一点,而 C++23 是不会神奇地赋予它这种能力。然而,字符串文字可能能够表示所有 Unicode,并且 C++23 不会剥夺这种能力(问题没有提到字符串文字,但恕我直言,这是一个很好的答案)。 (3认同)