繁体   English   中英

GCC 和 MSVC 中的 C++ utf-8 文字

[英]C++ utf-8 literals in GCC and MSVC

这里我有一些简单的代码:

#include <iostream>
#include <cstdint>

    int main()
    {
         const unsigned char utf8_string[] = u8"\xA0";
         std::cout << std::hex << "Size: " << sizeof(utf8_string) << std::endl;
          for (int i=0; i < sizeof(utf8_string); i++) {
            std::cout << std::hex << (uint16_t)utf8_string[i] << std::endl;
          }
    }

我在这里看到 MSVC 和 GCC 的不同行为。 MSVC 将"\\xA0"视为未编码的 unicode 序列,并将其编码为 utf-8。 所以在 MSVC 中,输出是:

C2A0

在 utf8 unicode 符号U+00A0中正确编码。

但是在 GCC 的情况下不会发生任何事情。 它将字符串视为简单字节。 即使我在字符串文字之前删除u8也没有任何变化。

如果字符串设置为: u8"\ ";则两个编译器都编码为带有输出C2A0的 utf8。

为什么编译器的行为不同,实际上哪个是正确的?

用于测试的软件:

海合会 8.3.0

MSVC 19.00.23506

C++ 11

他们都错了。

据我所知,C++17 标准在这里说:

窄字符串文字的大小是转义序列和其他字符的总数,加上至少一个用于每个通用字符名称的多字节编码,加上一个用于终止的 '\\0'。

尽管还有其他提示,但这似乎是转义序列不是多字节并且 MSVC 的行为错误的最有力的迹象。

有针对此的票证,目前标记为“正在调查”:

然而,它也在这里说关于 UTF-8 文字:

如果该值不能用单个 UTF-8 代码单元表示,则程序格式错误。

由于0xA0不是有效的 UTF-8 字符,因此程序不应编译。

请注意:

  • u8开头的 UTF-8 文字被定义为窄的。
  • \\xA0是一个转义序列
  • 被认为是通用字符名称而不是转义序列

为什么编译器的行为不同,哪个实际上是正确的?

编译器的行为不同,因为它们决定实现 C++ 标准的方式:

  • GCC 使用严格的规则并按原样实施标准
  • MSVC 使用松散的规则并以更实用的“现实世界”方式实现标准

所以在 GCC 中失败的事情通常会在 MSVC 中工作,因为它更被允许。 MSVC 会自动处理其中一些问题。

这是一个类似的例子: https : //gcc.gnu.org/bugzilla/show_bug.cgi?id=33167 它遵循标准,但不是您所期望的。

至于哪个做得对,取决于您对“正确”的定义是什么。

我不能告诉你哪种方式符合标准。

MSVC 的做法至少在逻辑上是一致且易于解释的。 三个转义序列\\x\\u\u003c/code>和\\U行为相同,除了它们从输入中提取的十六进制数字的数量:2、4 或 8。每个都定义了一个 Unicode 代码点,然后必须将其编码为 UTF-8。 嵌入一​​个没有编码的字节会导致创建无效的 UTF-8 序列的可能性。

这是CWG 问题 1656

在当前的标准草案中通过P2029R4解决了这个问题,以便将数字转义序列的值视为单个代码单元,而不是作为然后编码为 UTF-8 的 unicode 代码点。 即使它导致无效的 UTF-8 序列也是如此。

因此 GCC 的行为是/将是正确的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM