3

好的,我有这个:

AllocConsole();
SetConsoleOutputCP(CP_UTF8);
HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsoleA(consoleHandle, "aΕλληνικά\n", 10, NULL, NULL);
WriteConsoleW(consoleHandle, L"wΕλληνικά\n", 10, NULL, NULL);
printf("aΕλληνικά\n");
wprintf(L"wΕλληνικά\n");

现在,问题是根据编码文件被保存为这些作品中的一部分。wprintf 从不工作,但我已经知道原因(损坏的 Microsoft stdout 实现,它只接受窄字符)。然而,我和其他三个人有问题。如果我将文件保存为不带签名 (BOM) 的 UTF-8 并使用 MS Visual C++ 编译器,则只有最后一个 printf 有效。如果我想让 ANSI 版本正常工作,我需要将字符(?)计数增加到 18:

WriteConsoleA(consoleHandle, "aΕλληνικά\n", 18, NULL, NULL);

我认为,WriteConsoleW 不起作用,因为字符串被保存为 UTF-8 字节序列,即使我明确要求将其存储为带有 L 前缀的宽字符(UTF-16),并且实现很可能期望 UTF-16 编码的字符串不是UTF-8。

如果我将它保存在带有 BOM 的 UTF-8 中(应该如此),那么 WriteConsoleW 开始以某种方式工作(???)并且其他一切都停止(我得到 ? 而不是一个字符)。我需要将 WriteConsoleA 中的字符数减少回 10 以保持格式相同(否则我会得到 8 个额外的矩形)。基本上,WTF?

现在,让我们转到 UTF-16(Unicode - 代码页 1200)。仅适用于 WriteConsoleW。WriteConsoleA 中的字符数应为 10 以保持格式精确。

以 UTF-16 Big Endian 模式(Unicode - 代码页 1201)保存不会改变任何内容。再说一次,WTF?存储到文件时不应该反转字符串中的字节顺序吗?

结论是字符串被编译成二进制形式的方式取决于所使用的编码。因此,存储字符串的可移植且独立于编译器的方式是什么?是否有一个预处理器可以在编译之前将一种字符串表示形式转换为另一种表示形式,所以我可以将文件存储在 UTF-8 中,并且只通过将它们包装一些宏来预处理我需要在 UTF-16 中具有的字符串。

4

2 回答 2

0

据我所知,我认为您在这里至少有一些假设是错误的,或者不是 100% 正确:

现在,问题是根据编码文件被保存为这些作品中的一部分。

当然,因为编码决定了如何解释字符串文字。

wprintf 从不工作,但我已经知道原因(损坏的 Microsoft stdout 实现,它只接受窄字符)。

我从来没有听说过那个,但我很确定这取决于为您的程序设置的语言环境。我有一些工作项目,其中设置了语言环境并且使用德语变音符号等输出很好。

如果我将文件保存为不带签名 (BOM) 的 UTF-8 并使用 MS Visual C++ 编译器,则只有最后一个 printf 有效。如果我想让 ANSI 版本正常工作,我需要将字符(?)计数增加到 18:

这是因为 ANSI 版本需要一个 ANSI 字符串,而您传递的是 UTF-8 编码的字符串(基于文件的编码)。输出仍然有效,因为控制台会为您处理 UTF-8 转换 - 您实际上是在此处打印原始 UTF-8。

我认为,WriteConsoleW 不起作用,因为字符串被保存为 UTF-8 字节序列,即使我明确要求将其存储为带有 L 前缀的宽字符(UTF-16),并且实现很可能期望 UTF-16 编码的字符串不是UTF-8。

我不这么认为(尽管我不确定为什么它也不起作用)。您是否尝试过设置一些易于查找的字符串并在生成的二进制文件中查找它?我很确定它确实是使用 UTF-16 编码的。我假设由于缺少 BOM,编译器可能会将整个内容解释为一个窄字符串,因此将 UTF-8 内容转换为错误的。

如果我将它保存在带有 BOM 的 UTF-8 中(应该如此),那么 WriteConsoleW 开始以某种方式工作(???)并且其他一切都停止(我得到 ? 而不是一个字符)。我需要将 WriteConsoleA 中的字符数减少回 10 以保持格式相同(否则我会得到 8 个额外的矩形)。基本上,WTF?

这正是我上面描述的。现在宽字符串被正确编码,因为编译器现在知道文件是 UTF-8,而不是 ANSI(或某些代码页)。窄字符串也被正确转换为正在使用的语言环境。


总体而言,没有独立于编码的方法可以做到这一点,除非您提前使用正确的代码页和/或 UTF 代码对所有内容进行转义。我只是坚持使用带有 BOM 的 UTF-8,因为我认为所有当前的编译器都能够正确读取和解释文件(除了 Microsoft 的资源编译器;虽然我还没有尝试使用 UTF-8 提供 2012 版本)。

编辑:

打个比方:

您实际上是将原始图像保存到文件中,并且您希望它能够正常工作,无论其他程序是否尝试将其读取为灰度、调色板或全彩色图像。这不起作用(尽管差异较小)。

于 2013-04-06T09:55:23.333 回答
0

答案就在这里

报价:

编译器不可能将 UTF-8 和 UTF-16 字符串混合到编译输出中!所以你必须决定一个源代码文件:

  • 要么将 UTF-8 与 BOM 一起使用并仅生成 UTF-16 字符串(即始终使用 L 前缀),
  • 或不带 BOM 的 UTF-8,仅生成 UTF-8 字符串(即从不使用 L 前缀),
  • 不涉及 7 位 ASCII 字符,可以带或不带 L 前缀使用

唯一可移植且独立于编译器的方法是使用 ASCII 字符集和转义序列,因为不能保证任何编译器都会接受 UTF-8 编码文件,并且编译器对这些多字节序列的处理可能会有所不同。

于 2013-04-09T09:52:02.797 回答