Microsoft的C运行时库(CRT)不支持UTF-8作为区域设置编码。它只支持Windows代码页。此外,“es\u es”不是有效的CRT区域设置字符串,因此
setlocale
将失败,使您处于默认的C语言环境中。较新版本的Microsoft CRT支持Windows区域设置名称,如“es es”(连字符,而不是下划线)。否则,CRT使用全名或旧的三个字母缩写,例如“spanish\u Spania”、“esp\u esp”或“esp\u esp.1252”。
但这还不是故事的结局。当使用传统文本编码(而不是Unicode)从控制台读写时,控制台本身有另一层翻译。为了避免mojibake,您必须设置控制台输入和输出代码页(即。
SetConsoleCP
和
SetConsoleOutputCP
)以匹配区域设置代码页。如果您仅限于西班牙语或拉丁语-1,那么可以将语言环境设置为“西班牙语”,并通过以下方式设置控制台代码页
SetConsoleCP(1252)
和
SetConsoleOutputCP(1252)
。一般来说,您可以在ANSI代码页中查找给定的语言环境名称,设置控制台代码页,然后保存它们,以便在退出时重置控制台。例如:
wchar_t *locale_name = L"es-ES";
if (_wsetlocale(LC_ALL, locale_name)) {
int codepage;
gPrevConsoleCP = GetConsoleCP();
if (gPrevConsoleCP) { // The process is attached to a console.
gPrevConsoleOutputCP = GetConsoleOutputCP();
if (GetLocaleInfoEx(locale_name,
LOCALE_IDEFAULTANSICODEPAGE |
LOCALE_RETURN_NUMBER,
(LPWSTR)&codepage,
sizeof(codepage) / sizeof(wchar_t))) {
if (!codepage) { // The locale doesn't have an ANSI codepage.
codepage = GetACP();
}
SetConsoleCP(codepage);
SetConsoleOutputCP(codepage);
atexit(reset_console);
}
}
}
也就是说,在使用控制台时,如果设置
stdin
和
stdout
使用
_O_U16TEXT
模式并使用宽字符函数,例如
fgetws
和
wprintf
。最终,如果C运行时库支持,则应使用宽字符控制台I/O函数
ReadConsoleW
和
WriteConsoleW
。使用UTF-16宽字符模式的缺点是需要对代码进行完全重写才能使用
wchar_t
字符串和宽字符函数,还需要为使用多字节编码字符串(最好是UTF-8)的库实现适配器。