C++标准为C++标准IO库设计了十分完善的国际化文本处理机制。但在实际使用中,却发现各种编译器对它的支持性存在较大的差异,很多时候无法正确的输出字符。于是我对此进行了深入的调查。
测试程序
#include <stdio.h>
#include <clocale>
#include <wchar.h>
#include <string>
#include <iostream>
using namespace std;
const char* psa = "A汉字ABC";
const wchar_t* psw = L"W汉字ABC";
int main(int argc, char* argv[])
{
// init.
//ios::sync_with_stdio(false); // Linux gcc.
locale::global(locale(""));
//setlocale(LC_CTYPE, ""); // MinGW gcc.
wcout.imbue(locale(""));
// C++
cout << psa; cout.clear(); cout<<endl;
wcout << psw; wcout.clear(); wcout<<endl;
// C
printf("\nC:\n");
printf("\t%s\n", psa);
printf("\t%ls\n", psw);
return 0;
}
理论结果
先根据C++标准,分析一下这段程序的理论结果。
在main函数中,首先执行了这两行代码对地区环境进行了初始化——
locale::global(locale(""));
wcout.imbue(locale(""));
- locale(""):调用构造函数创建一个local,其中的空字符串具有特殊含义:使用客户环境中缺省的locale(《C++标准程序库—自修教程与参考手册》P697)。例如在简体中文系统上,会返回简体中文的locale。
- locale::global(locale("")):将“C++标准IO库的全局locale”设为“客户环境中缺省的locale”。注意它还会设置C标准库的locale环境,造成与“setlocale(LC_ALL, "")”类似的效果(《C++标准程序库—自修教程与参考手册》P698)。
- wcout.imbue(locale("")):使wcout使用“客户环境中缺省的locale”。
就这样,使C标准库、C++标准IO库(尤其是wcout)均正确的设置了地区环境,与客户环境中缺省环境完全匹配。
随后,使用C++标准IO库的cout、wcout分别输出窄字符串和宽字符串。
实际输出
VS 2015 / Windows 10
经过多次测试发现,VS2015中,如果对全局的locale进行了设置,则cout无法正常输出。我们应该采用下面这种办法设置
locale loc("");
wcout.imbue(loc);
通过这种办法,不会影响全局的locale设置,cout和wcout将都能正常输出。 对于这种问题,我真的是日了微软了。