免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4915 | 回复: 3
打印 上一主题 下一主题

【讨论】【i18n】wcout.imbue()不起作用和混用cout和wcout [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-02-23 11:35 |只看该作者 |倒序浏览
g++ 4.3.2
libstdc++6-4.3.2(runtime和开发库都用这个版本)
bash locale: en_US.UTF-8
源码用UTF-8保存
"中文"的UTF-8编码是:E4 B8 AD E6 96 87
UCS2 LE编码是:2D 4E 87 65

问题一:wcout.imbue()不起作用

代码:
  1. const wchar_t* strzh = L"中文abc"
  2. locale lc("");
  3. locale::global(lc);
  4. wcout << L"Zhong text is: " << strzh << endl;
复制代码
上面代码运行正常,终端输出中文,并且是UTF-8编码的:
  1. # ./test_03.exe | hd
  2. 00000000  5a 68 6f 6e 67 20 74 65  78 74 20 69 73 3a 20 e4  |Zhong text is: .|
  3. 00000010  b8 ad e6 96 87 61 62 63  0a                       |.....abc.|
  4. 00000019
复制代码
但如果不用locale::global(),而用: wcout.imbue(lc),就无法向终端传递有效的字符编码,结果是:
  1. # ./test_03.exe | hd
  2. 00000000  5a 68 6f 6e 67 20 74 65  78 74 20 69 73 3a 20 3f  |Zhong text is: ?|
  3. 00000010  3f 61 62 63 0a                                    |?abc.|
  4. 00000015
复制代码
终端得到的中文部分也不是UCS,而是被libstdc++转换错误的'?'字符。

问题二:cout和wcout无法混用

即使用locale::global(),如果在wcout之前用char版的流对象cout,也会出现向终端传送无效字符的情况,比如下面代码:
  1. const wchar_t* strzh = L"中文abc"
  2. locale lc("");
  3. locale::global(lc);
  4. cout << "abc" << endl;
  5. cout.flush();
  6. cout.clear();
  7. wcout.flush();
  8. wcout.clear();
  9. wcout << L"Zhong text is: " << strzh << endl;
复制代码
结果如下:
  1. # ./test_03.exe | hd
  2. 00000000  61 62 63 0a 5a 68 6f 6e  67 20 74 65 78 74 20 69  |abc.Zhong text i|
  3. 00000010  73 3a 20 2d 87 61 62 63  0a                       |s: -.abc.|
  4. 00000019
复制代码
上面的 2d 87 是 "中文" 的 UCS 编码的每个 wchar_t 的最低字节,看来在混用cout和wcout时,libstdc++转换wchar_t时犯错了,即使用flush()、clear()清流对象也不行。

如果把 cout << "abc" << endl; 这句放到 wcout 之后,那么 wcout 是可以正常输出中文的,但 cout 就工作不正常了,根本就不向终端传字符。

我以前混用C标准库的 printf() 和 wprintf() 时,就发现 glibc 有这个问题,没想到 libstdc++ 也有这问题。

我的感觉是 cout、wcout 还没有 printf()、wprintf() 好用,至少 printf()、wprintf() 都可以输出 wchar_t 型字符,而 cout 默认无法输出 wchar_t 型字符(当然可以自己重载 <<),而把 wchar_t 当整数输出,把 wchar_t[] 和 wchar_t* 输出个首地址。

wcout 可以输出 char,当用 wcout 输出 char[] 和 char* 时,如果其中的字符超过ASCII的范围(0x00-0x7F),则不会显示。

大家对上面两个问题有什么看法,欢迎讨论下。

论坛徽章:
0
2 [报告]
发表于 2010-02-23 14:27 |只看该作者
我用 VC8 测试了下,和 GNU libstdc++ 的差异挺大,表现结果是:wcout.imbue(lc) 起作用,可以在控制台中输出含中文的 wchar_t 型字符,并且控制台得到的是根据 locale 转换的 Native ANSI 编码,Windows 的 locale 类实现不支持 UTF-8,所以得到的是 GBK 编码,对应的 locale 名为 "chs"。

而用 VC8 的 locale::global(lc) 时有个奇怪的现象,它导致后面的 wcout 流输出到控制台完全没有显示,我将输出重定向到文件,发现结果正常,和用 imbue() 输出的相同,为 GBK 编码的中文,看来是 Windows 的控制台设备实现、以及和 CRT 交互的问题,CRT 本身是工作正常的。

最后又实验了 VC8 的 cout 和 wcout 的混用,以及 printf() 和 wprintf() 混用,都没有 GNU 实现的问题。

论坛徽章:
0
3 [报告]
发表于 2010-02-23 23:42 |只看该作者
直接强制规定必须UTF8,然后printf就OK,不用UTF8的滚蛋!

论坛徽章:
0
4 [报告]
发表于 2010-02-24 09:32 |只看该作者
因为 Windows 实现的标准库(C和C++都是) 是不支持 UTF-8 的(代码页.65001),为了程序好移植,所以想在程序内部用UCS保存字符,输出时根据 locale 转成合适的 Native ANSI,即 GBK 或 UTF-8
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP