【发布时间】:2013-03-28 18:28:27
【问题描述】:
好的,我有这个:
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 中具有的字符串。
【问题讨论】:
-
您的编译器是否支持 C99 的 \uXXXX 和 \UXXXXXXXX 转义以用于 unicode?虽然不可读,但它肯定更便携,因为只需要基本的 C 字符集。
-
@Jens Visual C++ 不符合 C99,只有 ANSI,但我可以试试。
-
这听起来有点令人困惑,我不能 100% 确定您要在这里做什么。您是否只想为窄字符和宽字符字符串保留一个字符串文字?或者您想在保持编码正常工作的同时混合/匹配两者?
-
@Mario 我想让源代码中的字符串可移植(独立于编码文件保存为)。如果我将它保存在 UTF-16 或 UTF-8 下并带有 BOM printf 停止工作,如果我将它保存在 UTF-8 下而没有 BOM printf 工作但 WriteConsoleW 停止会导致它们中的每一个都需要不同的编码字符串(我想)。
-
试图在下面解释您的一些问题。如果您仍然无法正确输出,请在答案下方的评论中告诉我,我会尝试仔细查看。