2013-04-05 109 views
8

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

我习惯使用Unicode(和wchar_t,wstring,wcin,wcout和L“...”)。我也用UTF-8保存源文件。

目前我使用MinGW(Windows 7)并在Windows控制台(cmd.exe)中运行我的程序,但有时我可以在GNU \ Linux上使用gcc,并在使用UTF-8编码的Linux控制台中运行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>和许多其他人。

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

+0

你想改变什么?你想改变线程语言环境吗?系统区域设置? UI语言?还是活动的代码页?对于线程,控制台或系统?有很多选项,远远超过单个'setlocale'函数所暗示的选项。你必须解释你想看到的*效果,然后才能告诉你什么开关可以翻转。 – 2013-04-05 05:26:16

+0

@CodyGray,我需要任何Unicode符号/字符串正确输入和outputed。这个_effect_的充分描述?我想,这意味着我需要更改程序启动的控制台的编码。 – 2013-04-05 15:09:54

+0

通常,我会说一个程序不应该修改语言环境 - 它应该在提供的语言环境中工作。否则,这种做法有悖于“国际化”的目的。 – 2013-04-06 00:51:45

回答

5

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

这当然是可能的,虽然使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... 
} 

您还必须将字体从包含必要的Unicode字符字形-e.g,龙力控制台或索拉(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咕噜声足够工作的一个答案!

0

我刚刚需要输出Unicode文本到控制台,只有这个功能WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), ...);帮助。对于输入,我假设ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), ...);有窍门。

PSWriteOutput在输出字符串大小上有限制。因此,如果时间更长,您可能需要将其重新分块。

相关问题