[英]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 中工作,因为它更被允许。 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.