【问题标题】:Is C++20 'char8_t' the same as our old 'char'?C++20 'char8_t' 和我们的旧 'char' 一样吗?
【发布时间】:2019-12-15 13:36:14
【问题描述】:

在 CPP 参考 documentation

我注意到char

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

对于char8_t

用于 UTF-8 字符表示的类型,需要足够大 表示任何 UTF-8 代码单元(8 位)

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

【问题讨论】:

  • 嗯,很明显char8_t 是一个 8 位类型。此外,char 的签名取决于编译器和目标平台:ARM 和 PowerPC 的默认值通常是无符号的,x86 和 x64 的默认值通常是有符号的。char8_t总是无符号。
  • " 还是 char8_t 有额外的优势?" - 你这是什么意思?
  • 嗯,有个好处。 char 类型,就像 C++ 的大部分 C 遗产一样,并且一直被令人讨厌地破坏。您不知道它是否已签名,而且非常严格地说,您甚至不知道它有多少位(尽管 8 是一个相当安全的赌注,但无法保证)。 char8_t 类型提供了这两种保证。不幸的是,没有人敢于简单地“修复”损坏的原始类型(诚然,这可能会破坏现有代码,但那又怎样......现代 C++ 无论如何都与传统 C++ 不兼容)。就像没有人愿意将size_tptrdiff_t 设为正确的 类型。
  • @Damon 根据this comment,没有要求char8_t 正好是八位,所以在这方面没有任何改变......
  • @Damon C 一直保证char至少 8 位。 POSIX 和大多数其他系统(如 Windows)保证 char 正好是 8 位。但是C确实说“是的,等等等等POSIX”。 POSIX 合并了 C 标准,而不是相反。除非 C 突然决定疏远其利基的很大一部分,否则他们不会强制要求精确的 8 位类型,因为 C 是用于编程所有字节大于 8 的现代嵌入式/利基硬件的主要语言位。

标签: c++ c++14 c++20


【解决方案1】:

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

在 C++20 中,char8_t 是不同于所有其他类型的类型。在 C 的相关提案中,N2653char8_tunsigned char 的 typedef,类似于 char16_tchar32_t 的现有 typedef。

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

特别是,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.

具有这些属性的不同类型的动机是:

  1. 为 UTF-8 字符数据与具有取决于区域设置或需要单独规范的编码的字符数据提供不同的类型。

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

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

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

【讨论】:

  • 为什么是 char8_t 而不是 uchar8_t?
  • 因为char8_tchar16_tchar32_t(也是无符号类型)一致。
【解决方案2】:

char8_tchar 不同。它的行为与unsigned char 完全相同,尽管根据[basic.fundamental]/9

类型char8_­t 表示其基础类型为unsigned char 的独特类型。类型char16_­tchar32_­t 表示不同类型,其基础类型分别为uint_­least16_­tuint_­least32_­t,在&lt;cstdint&gt;.

强调我的


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

std::cout << std::is_same_v<unsigned char, char8_t>;

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


另外需要注意的是char 可以实现为signed charunsigned char。这意味着char 可能具有与char8_t 相同的范围和表示,但它们仍然是不同的类型。 charsigned charunsigned charchar8_t 的大小相同,但它们都是不同的类型。

【讨论】:

  • @MichaelDorgan 但是 98 比 17 大,而且 98 是......不是很有趣;)
  • @MichaelDorgan 如果您不知道,C 还具有 char16_tchar32_t 以及相关的字符/字符串文字和操作函数。 (当然还有charunsigned charsigned charint8_tuint8_t
  • 那么,我们真的需要从已经存在的东西中取另一个名字吗?
  • @MichaelChourdakis:“那么,我们真的需要从已经存在的东西中取另一个名字吗?”是的。如果我给你一个const char*,它是 UTF-8 编码的吗?你不知道。如果我给你一个const char8_t *,那么如果它不是 UTF-8 编码,我是个骗子。类型很重要,如果 C++ 要获得体面的 Unicode 支持,我们必须有表示以 Unicode 编码编码的字符串的类型,而不仅仅是编译器的感觉。 char8_t 唯一真正的问题是很少有现有的 API可以 使用它们。随着 Unicode 的完成,这个问题将得到解决。
  • 有趣的是,没有要求 char8_t 正好是 8 位。由于它与unsigned char 具有相同的表示形式,因此它是CHAR_BIT 位。与 uint8_t 不同,如果没有 8 位整数类型,则不会定义 char8_t 始终定义。 (CHAR_BIT != 8 可能没有托管实现。)
猜你喜欢
  • 2011-12-26
  • 2019-12-27
  • 2018-05-09
  • 2020-09-10
  • 2012-06-23
  • 2012-07-16
  • 2019-09-30
  • 2023-01-26
  • 2013-12-12
相关资源
最近更新 更多