【问题标题】:MSVC UTF8 string encoding uses incorrect code pointsMSVC UTF8 字符串编码使用不正确的代码点
【发布时间】:2019-10-27 15:46:16
【问题描述】:

我正在尝试将字符“Ā” (https://www.fileformat.info/info/unicode/char/0100/index.htm) 写入 C++11 UTF8 字符串(使用 u8 前缀)。

const char *const utf8 = u8"Ā";
const char *const utf8_2 = u8"\u0100";
const char *const chars = "Ā";

const int utf8_len = strlen(utf8);
const int utf8_2_len = strlen(utf8_2);
const int chars_len = strlen(chars);

在 MSVC (16.2.4) 下运行会导致:

utf8_len == 5
utf8_2_len = 2;
chars_len = 2;

地点:

utf8 == "Ä€"
utf8_2 == "Ä€"
chars == "Ä€"

源文件设置为 UTF8(无 BOM)。

对 Clang 和 GCC 进行同样的尝试可以按预期工作:

https://godbolt.org/z/PNZFCa

有谁知道为什么会发生这种行为?为什么 u8 前缀的 Unicode 字符被编码为 5 个字节(应该是 2 个字节)?

【问题讨论】:

  • 可能是编译器错误。您是否考虑过举报?
  • 我的猜测是,它被双重编码。首先,文本编辑器将Ā 编码为两个字节"Ä€",然后编译器将其作为两个字符的Latin-1 字符串并进一步将每个字符编码为UTF-8。尝试将 .cpp 文件保存为“带签名的 UTF-8”,这样编译器就知道将源代码读取为 UTF-8 而不是 Latin-1。
  • @IgorTandetnik 使用 UTF8 BOM 保存确实可以解决此问题。在这种情况下,我认为这是一个编译器错误,所以我会报告它。
  • 这不是错误。大多数 Windows 程序假定文件是 ANSI 编码的,以便与旧版 Windows 使用向后兼容,并且需要 UTF-8 w/ BOM 来区分。
  • 这是一个合法的选择,但它仍然是一个 some 编码的文本文件,没有说明编码是什么。它“只是一堆字节”。大多数 Windows 程序,包括 MSVC 编译器,都假定文件的编码是本地化的 ANSI 编码,除非有 BOM。以字节 EF BB BF(以 UTF-8 编码的 U+FEFF Unicode BOM 字符)开头的文件是 UTF-8 文件。如果它以FF FE 开头,则它是一个 UTF-16LE 编码的文件,等等。没有 BOM,编译器假定为 ANSI。这就是/source-charset: 开关存在的原因。

标签: c++ c++11 visual-c++ unicode


【解决方案1】:

Microsoft 编译器假定没有 BOM 的文件使用本地 ANSI 编码,在您的情况下可能是 Windows-1252。如果您从命令行运行cl /?,您将看到以下命令行开关:

...
/source-charset:<iana-name>|.nnnn set source character set
/execution-charset:<iana-name>|.nnnn set execution character set
/utf-8 set source and execution character set to UTF-8
...

如果您不想使用 BOM 保存,请使用 /source-charset:UTF-8 或 /utf-8。

以 UTF-8 保存的测试代码,没有 BOM:

#include <stdio.h>
#include <string.h>

int main()
{
    const char *const utf8 = u8"Ā";
    printf("%zu\n",strlen(utf8));
}

输出:

C:\>cl /nologo test.cpp
test.cpp

C:\>test
5

C:\>cl /nologo /utf-8 test.cpp
test.cpp

C:\>test
2

【讨论】:

  • 谢谢,但我使用另存为(带编码)并选择了 UTF-8(不带 BOM)。所以我仍然相信这是一个错误。
  • @MarkIngram BOM 是告诉 Windows 程序文件以 UTF-8 编码的元数据。没有它,它可以保存为 Windows-1252 或 Windows-1251 或 UTF-8 或任何其他编码。除非另有说明,否则编译器采用 ANSI 编码(例如,Windows...US Windows == Windows-1252 版本的本地化编码)。
猜你喜欢
  • 2012-12-02
  • 1970-01-01
  • 2013-10-26
  • 1970-01-01
  • 1970-01-01
  • 2015-03-10
  • 2010-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多