Какой наиболее правильный способ установить кодировку на C++?

как лучше всего установить кодировку на C++?

я привык работать с Unicode (и wchar_t, wstring, wcin, wcout и L" ... "). Я также сохраняю источник в UTF-8.

на данный момент я использую MinGW (Windows 7) и запускаю свою программу в консоли Windows (cmd.exe), но иногда я могу использовать gcc на GNULinux и запускать promgram в консоли Linux с кодировкой UTF-8.

во все времена я хочу скомпилировать свой источник в Windows и Linux, и я хотите, чтобы все символы Unicode были правильно inputed и outputed.

когда я столкнулся со следующей проблемой с кодировками,я погуглил. И нашел самые разные советы: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> и многие, многие другие.

наконец-то меня обеспокоил этот шаманизм и я хочу спросить вас: как правильно установить кодировку?

2 ответов


мне нужно, чтобы любой символ/строка Unicode был правильно включен и отключен.

это, безусловно, возможно, хотя сделать консоль командной строки Windows правильно Unicode-aware требует некоторой специальной магии. Я серьезно сомневаюсь, что какая-либо из реализаций стандартных библиотечных функций будет делать это, к сожалению.

вы найдете несколько вопросов об этом при переполнении стека, но это хороший один. В основном консоль использует то, что по умолчанию называется (несколько ошибочно) кодовой страницей "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. Обычно, я бы посоветовал сильно против использования недокументированных функций, но я думаю, что здесь меньше проблем, так как вы бы только использовать его в старых версиях операционной система. Ты знаешь, ЧТО ЭТО НЕ ИЗМЕНИТСЯ. В более новых версиях, где он доступен, вы вызываете поддерживаемую функцию. Пример непроверенного кода:

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 Внутри. В любом случае, вы сами по себе для этого; заставляя окна мурлыкать, достаточно работы для одного ответа!


мне просто нужно было вывести Unicode text к консоли и только эта функция WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), ...); помогло. Для ввода я предполагаю ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), ...); делает трюк.

PS: WriteOutput имеет ограничение в размере выходной строки. Поэтому вы можете повторить его кусками, если он длиннее.