关于utf 8:如何在Windows上从c ++控制台应用程序打印UTF-8

How do I print UTF-8 from c++ console application on Windows

对于在英语Windows(XP,Vista或7)上使用Visual Studio 2008编译的C ++控制台应用程序。 是否可以打印到控制台并使用cout或wcout正确显示UTF-8编码的日语?


Windows控制台默认情况下使用OEM代码页显示输出。

要将代码页更改为Unicode,请在控制台中输入chcp 65001,或尝试使用SetConsoleOutputCP以编程方式更改代码页。

请注意,您可能必须将控制台的字体更改为在unicode范围内具有字形的字体。


这是MVP Michael Kaplan撰写的有关如何通过控制台正确输出UTF-16的文章。您可以将UTF-8转换为UTF-16并输出。


这应该工作:

1
2
3
4
5
6
7
8
9
10
11
#include <cstdio>
#include <windows.h>

#pragma execution_character_set("utf-8" )

int main()
{
    SetConsoleOutputCP( 65001 );
    printf("Testing unicode -- English -- Ελληνικ? -- Espa?ol -- Русский. a?bcdefghijklmno?pqrs?tuüvwxyz\
"
);
}

不知道它是否会影响任何内容,但是源文件被另存为Unicode(带签名的UTF-8)-代码页65001,位于文件->高级保存选项...。

将项目->属性->配置属性->常规->字符集设置为使用Unicode字符集。

有人说您需要将控制台字体更改为Lucida Console,但在我这边,Consolas和Lucida Console都显示了该字体。


我从未尝试过将控制台代码页设置为UTF8(不确定为什么它不起作用...控制台可以很好地处理其他多字节代码页),但是有几个功能需要看上:SetConsoleCP和SetConsoleOutputCP。

您可能还需要确保所使用的控制台字体能够显示您的字符。有SetCurrentConsoleFontEx函数,但仅在Vista及更高版本上可用。

希望能有所帮助。


仅用于其他信息:

" ANSI"是指Windows-125x,用于win32应用程序,而" OEM"是指控制台/ MS-DOS应用程序使用的代码页。
可以使用函数GetOEMCP()和GetACP()来检索当前活动的代码页。

为了正确地向控制台输出内容,您应该:

  • 确保当前的OEM代码页支持您要输出的字符
    (如有必要,请使用SetConsoleOutputCP进行正确设置)

  • 将字符串从当前的ANSI代码(win32)转换为控制台OEM代码页

  • 以下是一些实用的工具:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    // Convert a UTF-16 string (16-bit) to an OEM string (8-bit)
    #define UNICODEtoOEM(str)   WCHARtoCHAR(str, CP_OEMCP)

    // Convert an OEM string (8-bit) to a UTF-16 string (16-bit)
    #define OEMtoUNICODE(str)   CHARtoWCHAR(str, CP_OEMCP)

    // Convert an ANSI string (8-bit) to a UTF-16 string (16-bit)
    #define ANSItoUNICODE(str)  CHARtoWCHAR(str, CP_ACP)

    // Convert a UTF-16 string (16-bit) to an ANSI string (8-bit)
    #define UNICODEtoANSI(str)  WCHARtoCHAR(str, CP_ACP)


    /* Convert a single/multi-byte string to a UTF-16 string (16-bit).
     We take advantage of the MultiByteToWideChar function that allows to specify the charset of the input string.
    */

    LPWSTR CHARtoWCHAR(LPSTR str, UINT codePage) {
        size_t len = strlen(str) + 1;
        int size_needed = MultiByteToWideChar(codePage, 0, str, len, NULL, 0);
        LPWSTR wstr = (LPWSTR) LocalAlloc(LPTR, sizeof(WCHAR) * size_needed);
        MultiByteToWideChar(codePage, 0, str, len, wstr, size_needed);
        return wstr;
    }


    /* Convert a UTF-16 string (16-bit) to a single/multi-byte string.
     We take advantage of the WideCharToMultiByte function that allows to specify the charset of the output string.
    */

    LPSTR WCHARtoCHAR(LPWSTR wstr, UINT codePage) {
        size_t len = wcslen(wstr) + 1;
        int size_needed = WideCharToMultiByte(codePage, 0, wstr, len, NULL, 0, NULL, NULL);
        LPSTR str = (LPSTR) LocalAlloc(LPTR, sizeof(CHAR) * size_needed );
        WideCharToMultiByte(codePage, 0, wstr, len, str, size_needed, NULL, NULL);
        return str;
    }


    在应用程序启动控制台上,设置为默认OEM437 CP。
    我正在尝试将Unicode文本输出到stdout,其中控制台已切换到UTF8翻译_setmode(_fileno(stdout),_O_U8TEXT);而且即使使用Lucida TT字体,在屏幕上仍然没有运气。
    如果将控制台重定向到文件,则会创建正确的UTF8文件。

    最后我很幸运。我添加了单行" info.FontFamily = FF_DONTCARE;"现在正在工作。
    希望对您有帮助。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    void SetLucidaFont()
    {
        HANDLE StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
        CONSOLE_FONT_INFOEX info;
        memset(&info, 0, sizeof(CONSOLE_FONT_INFOEX));
        info.cbSize = sizeof(CONSOLE_FONT_INFOEX);              // prevents err=87 below
        if (GetCurrentConsoleFontEx(StdOut, FALSE, &info))
        {
            info.FontFamily   = FF_DONTCARE;
            info.dwFontSize.X = 0;  // leave X as zero
            info.dwFontSize.Y = 14;
            info.FontWeight   = 400;
            _tcscpy_s(info.FaceName, L"Lucida Console");
            if (SetCurrentConsoleFontEx(StdOut, FALSE, &info))
            {
            }
        }
    }

    在控制台中,输入chcp 65001将代码页更改为UTF-8。