我没有在 Windows 的 mingw 环境中使用 gcc,但据我所知,它不支持 C++ 语言环境。
由于它不支持 C++ 语言环境,这并不真正相关,但仅供参考,Windows 不使用与大多数其他平台相同的语言环境命名方案。它们使用类似的language_country.encoding,但语言和国家不是代码,编码是Windows 代码页号。因此语言环境将是“English_United States.65001”,但这不是受支持的组合(代码页 65001 (UTF-8) 不支持作为任何语言环境的一部分)。
只ws1
打印,而且只打印一次的原因是当打印字符时\u20AC
,流失败并且设置了失败位。您必须先清除错误,然后再打印任何内容。
C++11 引入了一些可移植处理 UTF-8 的东西,但还不是所有东西都支持,而且添加的东西并不能完全解决问题。但这是目前的情况:
当char16_t
和char32_t
在 VS 中作为原生类型而不是 typedef 被支持时,您将能够使用标准的 codecvt facet specializationscodecvt<char16_t,char,mbstate_t>
并且codecvt<char32_t,char,mbstate_t>
分别需要在 UTF-16 或 UTF-32 和UTF-8(而不是执行字符集或系统编码)。这还行不通,因为在当前的 VS(和 VS11DP)中,这些类型只是 typedef,模板专业化不适用于 typedef,但代码已经在 VS 2010 的标头中,只是在#ifdef
.
该标准还定义了一些支持的特殊用途的 codecvt facet 模板,codecvt_utf8 和 codecvt_utf8_utf16。前者根据您使用的宽字符类型的大小在 UTF-8 和 UCS-2 或 UCS-4 之间转换,后者在 UTF-8 和 UTF-16 代码单元之间转换,与宽字符的大小无关类型。
std::wcout.imbue(std::locale(std::locale::classic(),new std::codecvt_utf8_utf16<wchar_t>()));
std::wcout << L"ØÀéîðüýþ\n";
这将通过附加到 wcout 的任何内容输出 UTF-8 代码单元。如果输出已被重定向到文件,则打开它将显示一个 UTF-8 编码的文件。但是,由于 Windows 上的控制台模型,以及标准流的实现方式,这种方式将无法在命令提示符中正确显示 Unicode 字符(即使您使用 将控制台输出代码页设置为 UTF-8 SetConsoleOutputCP(CP_UTF8)
) . UTF-8 代码单元一次输出一个,控制台将查看传递给它的每个单独的块,期望传递的每个块(即在这种情况下为单个字节)是完整且有效的编码。当显示字符串时,块中不完整或无效的序列(在这种情况下是所有多字节字符表示的每个字节)将被替换为 U+FFFD。
如果不使用 iostreams 而是使用 C 函数puts
写出整个 UTF-8 编码字符串(并且如果控制台输出代码页设置正确),那么您可以打印 UTF-8 字符串并将其显示在控制台中。相同的 codecvt facets 可以与其他一些 C++11 convinence 类一起使用来执行此操作:
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> convert;
puts(convert(L"ØÀéîðüýþ\n).to_bytes().c_str());
上面的内容仍然不是很便携,因为它假设 wchar_t 是 UTF-16,在 Windows 上是这种情况,但在大多数其他平台上不是这样,而且它不是标准要求的。(实际上我的理解是它在技术上不符合标准,因为 UTF-16 需要多个代码单元来表示某些字符,并且标准要求所选编码中的所有字符都必须可以在单个 wchar_t 中表示)。
std::wstring_convert<std::codecvt_utf8<wchar_t>,wchar_t> convert;
以上将可移植地处理 UCS-4 和 USC-2,但不能在使用 UTF-16 的平台上的基本多语言平面之外工作。
您可以使用conditional
类型特征根据大小在这两个方面之间进行选择,wchar_t
并获得最有效的东西:
std::wstring_convert<
std::conditional<sizeof(wchar_t)==2,std::codecvt_utf8_utf16<wchar_t>,
std::codecvt_utf8<wchar_t>
>::type,
wchar_t
> convert;
或者,如果您的编码标准允许宏,则只需使用预处理器宏来定义适当的 typedef。