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

标签 c++ windows unicode encoding utf

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

我习惯于使用 Unicode(以及 wchar_twstringwcinwcout 和 L"... ")。我还以 UTF-8 格式保存源代码。

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

我一直想在 Windows 和 Linux 上编译我的源代码,我希望所有 Unicode 符号都能正确输入和输出。

当我遇到下一个编码问题时,我用谷歌搜索。我还发现了最不同的委员会: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>还有很多很多其他的。

终于被这种巫术所困扰,想请教各位:如何建立编码才是正确的?

最佳答案

I need that any Unicode symbol/string was correctly inputed and outputed.

这当然是可能的,尽管使 Windows 命令提示符控制台正确识别 Unicode 需要一些特殊的魔法。不幸的是,我严重怀疑标准库函数的任何实现是否会这样做。

您会在 Stack Overflow 上找到很多关于它的问题,但是 this one is a good one .基本上,控制台默认使用所谓的(有些错误地)“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.
    // ...
}

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

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

您还必须将默认字体(“Raster Fonts”)更改为包含必需的 Unicode 字符字形的字体,例如 Lucida Console 或 Consolas (reference)。使用 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);
    }
}

请注意,我将添加必需的错误检查作为读者的练习。这里的重点是技术和可读性;将其与错误处理混为一谈只会让事情变得困惑。

我不知道如何在 Linux 上执行这些操作。我怀疑它的工作要少得多,因为人们告诉我操作系统在内部使用 UTF-8。无论哪种方式,您都只能靠自己了;让 Windows 发出咕噜声就足以得到一个答案!

关于c++ - 在 C++ 中设置编码的最正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15826188/

相关文章:

c++ - 如何统计cpp文件中的所有全局变量

java - ConnectException(超时)使用 gradle 包装器运行 groovy Koans

Python 0xff 字节

java - charset=unicode 是 UTF-8、UTF-16 还是其他?

c++ - 模板化类的静态常量

c++ - "uFlags &= ~CHN_PANNING"命令有什么作用?

c++ - 继承将基类构造函数复制到派生类对象

python - VScode 看不到 pyenv python 解释器

windows - 将整个脚本输出重定向到文件并同时在控制台中显示

vb.net - 在 VB.NET 中显示向下的三角形 ▼ (U+25BC)