Какой наиболее правильный способ установить кодировку на 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
имеет ограничение в размере выходной строки. Поэтому вы можете повторить его кусками, если он длиннее.