【问题标题】:how can C++ wcout utf-16 encoded char array?C ++ wcout utf-16 编码的字符数组如何?
【发布时间】:2018-11-10 00:19:30
【问题描述】:

我正在阅读著名的answer 关于 string 和 wstring 的内容,但遇到了一些困惑。

source charset 和 execution charset 均设置为 utf-8,Windows x64,VC++ 编译器,git bash 控制台(可打印 unicode 字符),系统默认代码页 936(GB2312)。

我的专家代码:

#include <cstring>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
    wchar_t c[] = L"olé";
    wchar_t d[] = L"abc";
    wcout << c << endl;
    wcout << d << endl;

    return 0;
}

可以打印“abc”,但不能打印“é”。

我了解wchar_tL 前缀字符串文字一起使用。在 Windows 下,wchar_t 使用 UTF-16 编码(硬编码对吗?无论我选择什么源字符集或执行字符集,L"abc" 将始终具有相同的 UTF-16 代码单元)。

问题是:wcout怎么可能是一个UTF-16编码的字符串(“abc”),而我的源文件是utf-8,执行字符集是utf-8。除非我将所有内容都设置为 utf-16,否则程序应该无法识别 UTF-16 编码的内容。

如果它可以以某种方式打印 UTF-16,那为什么它不能打印é

【问题讨论】:

  • 我还没有测试过自己,因为这些天我无法在我的机器上编译 c++(我感到羞耻)。但我发现你的问题非常有趣,我用谷歌搜索了一下。我认为 M.M 是对的,这与控制台功能有关。查找特定于 Windows 的 _setmode(_fileno(stdout), _O_U16TEXT);... 我猜测 wcout 不会简单地转发 wchar_t* 而是进行一些翻译,这就是您看到正确打印某些字符而不是 é 的方式。
  • 是的,我知道 Windows 控制台不支持 utf-8。于是我在Git bash上试了一下(我觉得支持utf-8)。 windows控制台不是根本不支持utf-x吗?
  • Windows 控制台似乎支持 utf-8 字符,你可以在你的 cmd 上粘贴俄罗斯字符。我认为 wcout 可以轻松打印“abc”,因为在 ASCII、UTF-8 和 UTF-16 中,“a”在最后一个字节中编码为 0x61。 “b”和“c”几乎相同。但是 UTF-16 中的 "é" 是以 0xe9 结尾的,没有 UTF-8 字符以 0xe9 结尾。我想在 UTF-16 中的“é”和 UTF-8 中的“é”之间没有遗留或琐碎的翻译。如果您打算发送 UTF-16(并使用非传统字符),则需要将控制台设置为应用程序的标准输出

标签: c++ encoding


【解决方案1】:

Windows 控制台不支持 UTF-16 输出。它只支持 8 位输出,部分支持 8 位 MBCS,例如 Big5 或 UTF-8。

要在控制台上显示 Unicode 字符,您需要在代码中转换为 UTF-8 或其他 MBCS,并将控制台置于 UTF-8 模式(这需要未记录的系统调用)。

另见this answer

【讨论】:

  • 那我为什么要使用wchar_t而不是把所有东西都设置在utf-8下呢?我的意思是,它似乎没用。
  • @Rick 好吧,这取决于你。您可能希望使用它与 UTF-16 版本的 Windows API 进行交互,并使用控制台以外的其他输出方法(例如写入文件或窗口的 Windows API 调用)
  • 但是如何打印L"abc"?它们也使用 UTF-16 编码。
  • 我认为它输出 NUL 'a' NUL 'b' NUL 'c' 并且控制台会忽略空值
  • @Rick:对于任何使用普通文件 I/O API 的程序,它都支持 via code pages。如果有问题的程序知道如何使用the console I/O API(与常规文件 I/O API 分开),则该 API 提供对使用 UTF-16 的 Unicode 的完全支持,但该 API 并不为人所知,并且需要该程序使用 Windows 特定调用显式支持它(并通过检测句柄重定向动态选择使用文件或控制台 API)。
【解决方案2】:

您需要一个非标准的 Windows 系统调用来启用 UTF-16 输出。

#include <iostream>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>

int main()
{
    _setmode(_fileno(stdout), _O_U16TEXT); // <=== Windows madness
    std::wcout << L"olé\n";
}

请注意,您在执行此操作后不能使用cout,只能使用wcout

还要注意您的源代码文件必须有 BOM,否则编译器将无法将其识别为 Unicode。

【讨论】:

    猜你喜欢
    • 2020-07-17
    • 1970-01-01
    • 2016-10-02
    • 1970-01-01
    • 2012-04-01
    • 2014-01-18
    • 2012-10-12
    • 2013-09-11
    • 2010-10-16
    相关资源
    最近更新 更多