C ++ 20的“ char8_t”与旧的“ char”相同吗?

Pav*_*aka 31 c++ c++14 c++20

在CPP参考文档中

我注意到了 char

字符类型足够大,可以表示任何UTF-8八位代码单元(自C ++ 14起)

和为 char8_t

UTF-8字符表示形式的类型,必须足够大以表示任何UTF-8代码单元(8位)

这是否意味着两者是同一类型?还是char8_t有其他功能?

Nat*_*ica 39

char8_tchar。它的行为完全一样unsigned char虽然每[basic.fundamental] / 9

Type char8_­t表示其基础类型为的不同类型unsigned char。类型char16_­tchar32_­t分别表示不同的类型,其基本类型uint_­least16_­tuint_­least32_­t分别为,在<cstdint>.

重点矿


请注意,由于该标准将其称为不同类型,因此代码类似于

std::cout << std::is_same_v<unsigned char, char8_t>;
Run Code Online (Sandbox Code Playgroud)

0即使char8_t已实现为,也会打印(false)unsigned char。这是因为它不是别名,而是不同的类型。


要注意的另一件事是,char可以将其实现为signed charunsigned char。这意味着可能char具有与相同的范围和表示形式char8_t,但是它们仍然是单独的类型。 charsigned charunsigned char,和char8_t大小相同,但它们是完全不同的类型。

  • @MichaelChourdakis:“ *那么,我们实际上是否需要一个已经存在的名称的其他名称?*” 如果我给你一个“ const char *”,它是UTF-8编码的吗?你不知道 如果我改为给你一个“ const char8_t *”,那么如果它不是* UTF-8编码的,则“我是骗子”。类型很重要,而且如果C ++要获得体面的Unicode支持,我们必须具有表示以Unicode编码方式编码的字符串的类型,而不仅仅是表示编译器的感觉。“ char8_t”唯一真正的问题是*可以*接受它们的现有API很少。随着Unicode的完成,这一问题将得到解决。 (11认同)
  • 有趣的是,没有要求`char8_t`恰好是8位。由于它的表示形式与“ unsigned char”相同,因此它是“ CHAR_BIT”位。与不存在8位整数类型时不会定义的uint8_t不同,总是定义char8_t。(可能没有使用CHAR_BIT!= 8的托管实现。) (11认同)
  • @MichaelDorgan但是98比17大,而98则……与之合作并不是那么有趣;) (9认同)
  • @MichaelDorgan,如果您不知道,C还具有`char16_t`,`char32_t`以及关联的char / string文字和操作函数。(当然还有`char`,`unsigned char`,`signed char`,`int8_t`和`uint8_t`) (9认同)
  • @MichaelDorgan:与C的“兼容性”会增加复杂性吗?作为“ char”的标志问题。 (3认同)
  • 对于“完全相同”的定义。char8_t的一个关键特性是它不会在阳光下为所有事物起别名。 (3认同)
  • 那么,实际上我们是否需要一个已经存在的名称来命名? (3认同)
  • @Holger:“CHAR_BITS”*至少*8。假设我们正在处理“CHAR_BITS”是(例如)9的实现,并且我们的UTF-8编码文本通过网络到达。对“read”的调用(或任何调用的网络原语)将从网络接收八位字节,并将它们以 9 位字节的形式存储在内存中(使用该词的 C++ 标准含义)。类似地,包含 UTF-8 的文件会将每个 UTF-8 子单元存储在 9 位字节中(带有前导零位)。该文件不会将九个 UTF-8 单元打包为八个 9 位字节。(或者至少,除非有人犯傻,否则不会)。 (2认同)
  • @Holger正如Martin所说,传入的UTF-8数据可能必须以字节而不是八位位组存储。至于写入输出,我的猜测是,将数据写入文本流会将其剥离为 8 位,但写入二进制流将保留所有“CHAR_BIT”位(因为您必须能够读回与您相同的二进制数据)写道)。但这不太重要,因为据我所知,所有托管实现都有“CHAR_BIT==8”。(某些 DSP 将“CHAR_BIT”设置为 16 或 32,但它们不是托管的,因此不必支持标准 I/O。) (2认同)
  • @KeithThompson,但这是否意味着应用程序必须使用特殊函数读取 UTF-8 输入,或者是无符号字节和“UTF-8 单位”,即“char8_t”,即使在那些奇异的系统上也可以互换?我也有一种感觉,这几乎不重要,但是,C++ 标准委员会给程序员带来这样的负担一定是有原因的…… (2认同)

Tom*_*ann 18

免责声明:我是char8_t P0482P1423提案的作者。

在C ++ 20中,char8_t是与所有其他类型不同的类型。在用于C,相关提案N2231(这是需要的更新和重新提议WG14的),char8_t将是一个typedef unsigned char类似于用于现有的typedef char16_tchar32_t

在C ++ 20中,char8_t具有匹配的基础表示unsigned char。因此,它的大小(至少8位,但可能更大),对齐方式和整数转换等级与相同unsigned char,但具有不同的别名规则。

特别是,char8_t未将其添加到[basic.lval] p11的类型列表中。[basic.life] p6.4[basic.types] p2[basic.types] p4。这意味着,不同于unsigned char,它不能用于其他类型的对象的基础存储,也不能用于检查其他类型的对象的基础表示。换句话说,它不能用于别名其他类型。这样做的结果是该类型的对象char8_t可以通过指针被访问以charunsigned char,但指针char8_t不能用于访问charunsigned char数据。换一种说法:

reinterpret_cast<const char   *>(u8"text"); // Ok.
reinterpret_cast<const char8_t*>("text");   // Undefined behavior.
Run Code Online (Sandbox Code Playgroud)

具有这些属性的独特类型的动机是:

  1. 为UTF-8字符数据和字符数据提供不同的类型,其编码取决于语言环境或需要单独的规范。

  2. 为普通字符串文字和UTF-8字符串文字启用重载(因为它们可能具有不同的编码)。

  3. 确保UTF-8数据的无符号类型(char实现是定义有符号还是无符号)。

  4. 通过非混叠类型实现更好的性能;优化器可以更好地优化不别名其他类型的类型。

  • 为什么是 char8_t 而不是 uchar8_t? (9认同)
  • 因为`char8_t`与`char16_t`和`char32_t`一致(也是无符号类型)。 (4认同)