1
#include <iostream>

using namespace std;

void f1()
{
    wcout.imbue(locale("chs"));
    wcout << L"您" << endl;
}

void f2()
{
    locale loc(wcout.getloc(), new codecvt<wchar_t, char, mbstate_t>());

    wcout.imbue(loc);
    wcout << L"好" << endl;
}

int main()
{
    f1(); // OK
    f2(); // Error. There is no output as expected.
}

According to cplusplus.com's online documentation:

codecvt<wchar_t,char,mbstate_t>: 

    converts between native wide and narrow character sets.

This program is compiled with VC++, and runs on Windows.

In this program, the internal character set is UCS-2, which is defined by the VC++ compiler; the external character set, i.e. the narrow character set, is GBK (a Chinese character set) in console environment. If the documentation is true, then wcout can convert the unicode string from UCS-2 to GBK as f1() does; however, it does not. Why?

xmllmx
  • 39,765
  • 26
  • 162
  • 323

1 Answers1

5

You've default-constructed an std::codecvt, with no particular conversion rules. It has no way of knowing that you want GBK and not GB18030 or UTF-8.

Ways to get a codecvt that converts wchar_t to GBK:

  • Construct an std::locale for GBK just use that with your stream, no need to pull out a facet

    wcout.imbue(std::locale("")); // this uses the current user settings,
    wcout.imbue(std::locale("zn_CN.gbk")); // or name the locale explicitly,
                                           // by whatever name Windows calls it
    
  • Construct the facet directly with std::codecvt_byname

    wcout.imbue(std::locale(wcout.getloc(),
                new std::codecvt_byname("zh_CN.gbk")); // explict name
    
  • Write your own conversion routine and derive from std::codecvt, so you could use it with

    wcout.imbue(std::locale(wcout.getloc(), new yourcodecvt);
    

Windows support for C++ locales is very poor, though, WinAPI may have a more appropriate conversion function.

Cubbi
  • 46,567
  • 13
  • 103
  • 169