在C++中设置编码的最正确方法是什么?

sha*_*ote 8 c++ windows unicode encoding utf

如何最好在C++中设置编码?

我习惯了使用Unicode(和工作wchar_t,wstring,wcin,wcout和L "...").我还以UTF-8保存了源代码.

目前我使用MinGW(Windows 7)并在Windows控制台(cmd.exe)中运行我的程序,但有时我可以在GNU\Linux上使用gcc并在Linux控制台中使用UTF-8编码运行promgram.

在任何时候我都希望在Windows和Linux上编译我的源代码,我希望所有的Unicode符号都被正确地输入和输出.

当我遇到编码的下一个问题时,我用Google搜索.此外,我发现的最不同的委员会:setlocale(LC_ALL, "")setlocale(LC_ALL, "xx_XX.UTF-8"),std::setlocale(LC_ALL, "")std::setlocale(LC_ALL, "xx_XX.UTF-8")<clocale>,

SetConsoleCP()SetConsoleOutputCP()<windows.h>和许多其他人.

最后我被这种萨满教所困扰,我想问你:如何建立编码是正确的?

Cod*_*ray 6

我需要任何Unicode符号/字符串被正确输入和输出.

这当然是可能的,虽然使Windows命令提示控制台正确地识别Unicode会带来一些特殊的魔力.遗憾的是,我严重怀疑标准库函数的任何实现都会这样做.

你会在Stack Overflow上找到一些关于它的问题,但是这个问题很好.基本上,控制台默认使用所谓的(稍微错误地)"OEM"代码页.您希望将其更改为UTF-8代码页,其值由其定义CP_UTF8.为此,您需要同时调用SetConsoleCP函数(设置输入代码页)和SetConsoleOutputCP函数(设置输出代码页).代码看起来像这样:

if (!SetConsoleCP(CP_UTF8))
{
    // An error occurred; handle it. Call GetLastError() for more information.
    // ...
}
if (!SetConsoleOutputCP(CP_UTF8))
{
    // An error occurred; handle it. Call GetLastError() for more information.
    // ...
}
Run Code Online (Sandbox Code Playgroud)

为了获得额外的健壮性,您可能还需要确保首先支持UTF-8代码页,然后再尝试设置和使用它.你可以通过调用IsValidCodePage函数来做到这一点.例如:

if (IsValidCodePage(CP_UTF8))
{
    // We're all good, so set the console code page...
}
Run Code Online (Sandbox Code Playgroud)

您还必须将字体从默认字体("光栅字体")更改为包含必需的Unicode字符字形的字体 - 例如,Lucida Console或Consolas(参考).使用该SetCurrentConsoleFontEx功能是微不足道的.

不幸的是,在Vista之前的Windows版本中不存在此功能.如果您绝对需要支持这些较旧的操作系统,我唯一知道的就是调用未记录的SetConsoleFont函数.通常情况下,我会建议强烈反对使用未记录的函数,但我认为这不是一个问题,因为你只会在旧版本的操作系统中使用它.你知道那些不会改变.在可用的较新版本上,您可以调用支持的功能.未经测试的代码示例:

bool IsWinVistaOrLater()
{
    OSVERSIONINFOEX osvi;
    osvi.dwOSVersionInfoSize = sizeof(osvi);
    GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&osvi));

    if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
    {
        return osvi.dwMajorVersion >= 6;
    }
    return false;
}

void SetConsoleToUnicodeFont()
{
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    if (IsWinVistaOrLater())
    {
        // Call the documented function.
        typedef BOOL (WINAPI * pfSetCurrentConsoleFontEx)(HANDLE, BOOL, PCONSOLE_FONT_INFOEX);
        HMODULE hMod = GetModuleHandle(TEXT("kernel32.dll"));
        pfSetCurrentConsoleFontEx pfSCCFX = (pfSetCurrentConsoleFontEx)GetProcAddress(hMod, "SetCurrentConsoleFontEx");

        CONSOLE_FONT_INFOEX cfix;
        cfix.cbSize       = sizeof(cfix);
        cfix.nFont        = 12;
        cfix.dwFontSize.X = 8;
        cfix.dwFontSize.Y = 14;
        cfix.FontFamily   = FF_DONTCARE;
        cfix.FontWeight   = 400;  // normal weight
        lstrcpy(cfix.FaceName, TEXT("Lucida Console"));

        pfSCCFX(hConsole,
                FALSE, /* set font for current window size */
                &cfix);
    }
    else
    {
        // There is no supported function on these older versions,
        // so we have to call the undocumented one.
        typedef BOOL (WINAPI * pfSetConsoleFont)(HANDLE, DWORD);
        HMODULE hMod = GetModuleHandle(TEXT("kernel32.dll"));
        pfSetConsoleFont pfSCF = (pfSetConsoleFont)GetProcAddress(hMod, "SetConsoleFont");
        pfSCF(hConsole, 12);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我已经将所需的错误检查添加为读者的练习.这里的重点是技术和可读性; 将错误处理弄得乱七八糟只会让事情变得混乱.

我不知道如何在Linux上执行任何此操作.我怀疑这项工作少得多,因为人们告诉我操作系统内部使用UTF-8.无论哪种方式,你都是靠自己的; 制作Windows呜呜声就足以解决一个问题!