【问题标题】:MSVC is double-encoding UTF-8 strings, why?MSVC 是双重编码 UTF-8 字符串,为什么?
【发布时间】:2021-12-17 11:57:57
【问题描述】:

所以,这里有一些简单的代码来重新创建我的问题:

#include <cstdio>

const char* badString = u8"aš𒀀"; 
const char* anotherBadString = u8"\xef\x96\xae\xef\x96\xb6\x61\xc5\xa1\xf0\x92\x80\x80";
const char* goodString = "\xef\x96\xae\xef\x96\xb6\x61\xc5\xa1\xf0\x92\x80\x80";

void printHex(const char* str)
{
    for (; *str; ++str)
    {
        printf("%02X ", *str & 0xFF);
    }
    puts("");
}

int main(int argc, char *argv[])
{
    printHex(badString);
    printHex(anotherBadString);
    printHex(goodString);

    return 0;
}

我希望所有这些字符串都打印出相同的结果,EF 96 AE EF 96 B6 61 C5 A1 F0 92 80 80 。但是,在 MSVC 2019 中,前两个字符串会打印出 C3 AF C2 96 C2 AE C3 AF C2 96 C2 B6 61 C3 85 C2 A1 C3 B0 C2 92 C2 80 C2 80。这似乎是由于额外时间编码为 UTF-8 造成的。

我在other threads 中读到,解决此问题的方法是将/utf-8 标志添加到项目中,但我已经尝试过了,但没有任何区别。这里有什么我不理解的更基本的东西吗?

非常感谢!

【问题讨论】:

  • 我必须承认,您暴露的goodString 是我真正信任的唯一形式。它仅基于 ASCII 字符(不是编码的内容,而是它在源代码文件中的存储方式)。如果此类文件与不同平台上的不同编辑器和工具一起使用,则这些工具都不会对其内容造成任何损害。由于我对此的偏执,我什至使用八进制序列而不是十六进制,因为前者限制为 3 位,后者可能有 2 位或更多位。因此,如果十六进制序列与任意 ASCII 字符(我的意思是非十六进制序列)混合,后者可能会中断。

标签: c++ string visual-c++ encoding


【解决方案1】:

第一个字符串的第一个字符为ï(U+00EF,Latin Small Letter I With Diaeresis),其UTF-8编码为C3 AF

您显然希望第一个字符串以 U+F5AE 开头,但是您打开源文件的任何编辑器都同意 MSVC 不以该字符开头。

源文件可能被编码为带有BOM 的UTF-8,这就是/utf-8 标志不会改变任何东西的原因。该字符串在某些时候被损坏了,现在它的损坏形式在文件中得到了忠实的表现,MSVC 也在编译的代码中忠实地保留了它。

第二个字符串以\xef 开头,MSVC 将其解释为等同于\u00ef,即ï。我在 C++20 草案标准中找不到任何关于 \x 在 UTF-8 字符串中的含义的明确声明(尽管我看起来并不难)。从实验来看,似乎除了 MSVC 之外的大多数编译器都将 \x 后跟十六进制数字视为文字字节,即使这会使字符串无效 UTF-8。我认为你不应该在u8 前缀字符串中使用\x,因为它不可移植(可能除了\x00\x7f)。如果你想要 U+F5AE 那就写\uf5ae

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-27
    • 2011-08-09
    • 1970-01-01
    • 1970-01-01
    • 2012-09-11
    • 2010-12-01
    • 2011-08-17
    • 2014-01-18
    相关资源
    最近更新 更多