在将遗留代码移植到 C++20 时,我将字符串文字(带有预期的 UTF-8 编码文本)替换为 UTF-8 字符串文字(前缀为u8)。
因此,我遇到了八进制序列的问题,我过去用它来逐字节编码 UTF-8 序列:
\n虽然
\n"\\303\\274"是 的正确编码\xc3\xbc,但
\nu8"\\303\\274"最终以\xc3\x83\xc2\xbc.
我对此进行了进一步调查,并在cppreference.com上发现:
\n\n\n\n
(强调我的)
\n用我自己的话说:在 UTF-8 字符串文字中,八进制 ( \\ooo) 和十六进制 ( \\xXX) 转义序列被解释为 Unicode 代码点,类似于 Unicode 序列 (\\uXXXX和\\UXXXXXXXX)。
因此,这对我来说似乎是合理的:对于 UTF-8 字符串文字,Unicode 转义序列应该优于按字节的八进制序列(我过去使用过)。
\n出于好奇(并且出于演示的目的),我对 coliru 做了一个小测试,并惊讶地发现使用g++ -std=c++20,八进制序列仍然被解释为单个字节。考虑到上面的内容,我得出结论:
MSVC似乎是正确的,而g++是错误的。
\n我制作了一个 MCVE,并在本地 Visual Studio 2019 中运行:
\n#include <iostream>\n#include <string_view>\n\nvoid dump(std::string_view text)\n{\n const char digits[] = "0123456789abcdef";\n for (unsigned char c : text) {\n std::cout << \' \'\n << digits[c >> 4]\n << digits[c & 0xf];\n }\n}\n\n#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\\n"; __VA_ARGS__ \n\nint main()\n{\n DEBUG(const char* const text = "\\344\\270\\255");\n DEBUG(dump(text));\n std::cout << \'\\n\';\n DEBUG(const char8_t* const u8text = u8"\\344\\270\\255");\n DEBUG(dump((const char*)u8text));\n std::cout << \'\\n\';\n DEBUG(const char8_t* const u8textU = u8"\\u4e2d");\n DEBUG(dump((const char*)u8textU));\n std::cout << \'\\n\';\n}\nRun Code Online (Sandbox Code Playgroud)\nMSVC的输出:
\nconst char* const text = "\\344\\270\\255";\ndump(text);\n e4 b8 ad\nconst char8_t* const u8text = u8"\\344\\270\\255";\ndump((const char*)u8text);\n c3 a4 c2 b8 c2 ad\nconst char8_t* const u8textU = u8"\\u4e2d";\ndump((const char*)u8textU);\n e4 b8 ad\nRun Code Online (Sandbox Code Playgroud)\n(请注意,第一个和第三个文字的转储是相同的,而第二个转储则通过将每个八进制序列解释为 Unicode 代码点来生成 UTF-8 序列。)
\n相同的代码在 Compiler Explorer 中运行,使用g++ (13.2)编译:
\nconst char* const text = "\\344\\270\\255";\ndump(text);\n e4 b8 ad\nconst char8_t* const u8text = u8"\\344\\270\\255";\ndump((const char*)u8text);\n e4 b8 ad\nconst char8_t* const u8textU = u8"\\u4e2d";\ndump((const char*)u8textU);\n e4 b8 ad\nRun Code Online (Sandbox Code Playgroud)\n相同的代码在 Compiler Explorer 中运行,使用clang (17.0.1)编译:
\nconst char* const text = "\\344\\270\\255";\ndump(text);\n e4 b8 ad\nconst char8_t* const u8text = u8"\\344\\270\\255";\ndump((const char*)u8text);\n e4 b8 ad\nconst char8_t* const u8textU = u8"\\u4e2d";\ndump((const char*)u8textU);\n e4 b8 ad\nRun Code Online (Sandbox Code Playgroud)\n\n我的结论是否正确,即 MSVC 根据 C++ 标准正确,而不是 g++ 和 clang?
\n之前通过网络搜索发现:
\n\n使用十六进制转义序列而不是八进制序列不会改变任何内容:编译器资源管理器上的演示。
\n我更喜欢某种不寻常的八进制序列,因为它们仅限于 3 位数字,没有不相关的字符可能会无意中将它们扩展为 \xe2\x80\x94 ,与十六进制序列相反。
\n更新:
\n当我准备为 MSVC 提交错误时,我意识到这已经完成了:
\n unicode 字符串文字中的转义序列被过度编码(不符合 => 编译器错误)
| 归档时间: |
|
| 查看次数: |
153 次 |
| 最近记录: |