控制台输出Unicode中文的方法http://blog.sina.com.cn/s/blog_711203fb0100s7h9.html



C 使用wprintf,_tprintf 打印简体中文的方法 【Locale.h】{

char* paName = " 测试中";
wchar_t* pwName = L" 测试中";
printf(paName); // 输出为:测试中
wprintf((wchar_t*)paName); // 输出为:空
printf((char*)pwName); // 输出为:乱码
wprintf(pwName); // 输出为:空
}

如果将程序改写如下,则输出的结果就不一样了

#include <locale>

包含头文件先

{
char* paName = " 测试中";
wchar_t* pwName = L" 测试中";
setlocale(LC_ALL, "chs");
printf(paName); // 输出为:测试
wprintf((wchar_t*)paName); // 输出为:空
printf((char*)pwName); // 输出为:乱码
wprintf(pwName); // 输出为:测试
}
从上面两个代码片断可以看出:setlocale()对printf()没有影响,同时对char*的字符串也没有影响。唯一受到影响的是wprintf()这个函数了。我通过调试器查看了paName和pwName的字符,他们分别是:

paName :b2e2 cad4 d6d0 …… 应该是CHS编码(也就是代码页936)

-------------------

以上是网上找到的解决方法

转自:http://www.cnblogs.com/niuniu502/archive/2009/02/17/1392636.html

3、printf和wprintf

  加上这两位C语言中的老兄,问题更加复杂。考虑如下语句(注意s的大小写):

   printf("%s", "multibyte中文\n"); //
   printf("%S", L"unicode中文\n"); //
   wprintf(L"%S", "multibyte中文\n"); //
   wprintf(L"%s", L"unicode中文\n"); //

  缺省情况下,⑤、⑦两条语句不能输出中文,这两条语句中字符串的形式是unicode形式的。如果在所有输出语句之前加上如下语句将C语言的全局locale设置为本地语言(C语言中只有全局locale)就可以正常输出了:

  setlocale(LC_CTYPE, ""); //

  但这会导致cout和wcout不能输出中文(汗,的确麻烦),将C语言的全局locale恢复后cout和wcout就正常了,如下所示:

  setlocale(LC_CTYPE, "C"); //

  但恢复后,printf和wprintf输出Unicode文本又不正常了(输出MultiByte文本总是正常的)。总不能每写一个 printf/wprintf就设置一次然后再恢复一次吧?所以,建议不要混用iostream和printf/wprintf,实在要混用,那就让 printf/wprintf只输出MultiByte字符串,这样不需要调用setlocale(),也就不会影响到cout和wcout。

总结

  总之,用iostream、printf/wprintf输出中文,有点麻烦。概括起来要点如下:

如果要用wcout,需要在使用之前按语句①将其locale设置为本地语言;如果要用ofstream或wofstream,要在打开文件之前按语句②将全局locale设为本地语言并保存初始的全局locale。然后在打开文件之后,按语句③将全局locale恢复为初始值;不要混用iostream和printf/wprintf。如果要混用,只用printf/wprintf输出MultiByte字符串;单独使用printf/wprintf时,如果要输出Unicode字符串,需要按语句⑧设置C语言的全局locale。如果只输出MultiByte字符串,则不需设置。

为什么 wprintf 无法打印中文?

大学时就遇到这个问题,觉得很奇怪,为什么明明 Windows NT 系列内核都是使用 Unicode 的,而且在中文系统下跑,怎么反而无法输出汉字?虽然那时候鼓浪听涛上有前辈给出了提示,但还是不明白怎么会有这么 BT 的 CRT……

  最近看了《C99 规范》才明白了,原来这是“规范”规定的(C99 这样规定,C89 应该也有吧,谁证实一下?):

At program startup, the equivalent of
setlocale(LC_ALL, "C");
is executed.

  所以,setlocale(LC_CTYPE, NULL); 会返回一个 "C"。

  常规的解决方法是在程序入口处加下面这句代码:

setlocale(LC_CTYPE, "chs");

  但这样写要是用户在繁体版系统下运行岂不是出问题了,枉费了 Unicode 的好处,我发现用下面两个更好:

TCHAR szACP[16];
wsprintf(szACP, _T(".%d"), GetACP());
_tsetlocale(LC_CTYPE, szACP);

setlocale(LC_CTYPE, "");// 这个方案有待测试,谁帮我在英文版、繁体中文版上测一下?

  个人不太相信 CRT,不过也没办法,流行嘛……

wsprintf

函数作用:
  函数wsprintf()将一系列的字符和数值输入到缓冲区。
  输出缓冲区里的的值取决于格式说明符(即"%")。
  如果写入的是文字,此函数给写入的文字的末尾追加一个'\0'。
  函数的返回值是写入的长度,但不包括最后的'\0'。
  语法:
  int wsprintf(
  LPTSTR lpOut, // 输出缓冲区,最大为1024字节
  LPCTSTR lpFmt, // 格式字符串
  ...) // 需输出的参数;
  ;多少个参数都可以的,最起码前两个必须有
  我们在接触C语言的时候还接触过一个sprintf()的函数,
  用法和wsprintf()基本一样,区别在于:
  wsprintf()包含在头文件windows.h中
  sprintf()包含在头文件stdio.h中。
  wsprintf 其实分为 wsprintfA 和 wsprintfW,前者对应 sprintf,后者对应 wsprintf。
  wsprintf 有 1024 字符限制,而且不支持浮点数。
  所以注意了,该函数不支持浮点数的输入输出

关于%s和%ls的区别

我搜到了一篇帖子(很伤感,我再此发现在CS领域,最靠的住的资料总是英文的),里面对各种格式转换符有详细的解释,愿意看原文的同学直接忽略本段文字.......

http://www-ccs.ucsd.edu/c/lib_prin.html

首先,%ls和%s的区别很简单,%ls意味着将对应的参数会被当作基于宽字符的字符串(wide chraracter string )看待,而%s则意味着对应的参数会被当作普通字符串(multi-byte string)看待。

其次,不要因为上面一句话而错误的认为%s只用于printf,而%ls只用于wprintf 。实际上,(printf, wprintf) 和(%s,%ls)这两个元组之间是相互独立的,也就是说它们之间的四种组合都是可以的。

再次,printf用于byte stream,即输出流中的每个字符颤1 byte;而wprintf则用于wide stream,输出流中的每个字符不止 1 byte。

说了一堆废话,还是结合实例来看看%ls和%s的区别吧

例子1 printf + %s + wstr

printf( " %s " ,wstr);

whodare@whodare:$ .
/ a. out
- N


哈,这个郁闷的"-N"又一次出现!为什么会出现呢?让我来分析一下printf在执行时所完成的操作吧。

这里用了%s, printf 就会将对应的参数wstr视为普通字符串(尽管我们清楚他是个wcs而不是mbs);另一方面,我们已经看到了wstr[ ]的内存布局,其前3 byte为 0x2d ,0x4e,0x00。我们都知道C中的字符串以'\0'为结束标志,因此printf只会处理wstr[ ]中的前三个byte,而查一查ASCII表,0x2d对应字符'-',0x4e对应字符'N',所以我们会看到”-N"这个诡异的输出。

例子2 printf + %ls + wstr

printf( " %ls " ,wstr);

whodare@whodare:$ .
/ a. out
中文



使用了%ls,printf会将对应的参数视为宽字符串(wcs),而printf又对应byte stream,因此这里要对宽字符(wcs)进行转换,变成普通的字符串(mbs)。这里的转换是printf通过对每个宽字符隐式的调用wcrtomb ()这个标准库函数完成的。按么,wcrtomb()这个函数进行是按照什么规则进行转换的?这就是setlocale()的作用所在了,wcrtomb 会依据程序员设定的locale,将wcha_t中存放的码值,转换为相应的的多字节编码。

回到例子中,我的机器的locale为zh_CN.UTF-8,对应的编码为UTF-8,因此wstr[ ]中存放的Unicode码值会转换为UTF-8编码的形式输出到标准输出流中,这样采用UTF-8编码的console就能正确识别受到的字节流并显示出"中文"

例子3 wprintf + %s +wstr (最初的代码!)
wprintf(L " %s " ,wstr);

whodare@whodare:$ .
/ a. out
- N



使用了%s,wprintf会将对应的参数视为普通字符串mbs,尽管我们还是很清楚它其实是个wcs。 wprintf 使用的是wide stream,因此需要将所给的mbs参数转换为wcs再由wprintf完成输出;这个转换是由wprintf隐式的对mbs不断调用mbrtowc来完成,转换规则依然是和locale相关的。


我们知道wstr的内存布局为:
0x2d 0x4e 0x00 0x00
0x87 0x65 0x00 0x00
0x00 0x00 0x00 0x00

该"mbs"的转换结果为 L‘0x2d' + L '0x4e' + L '0x00' ,最终输出结果又是讨厌的"-N"

例子4 wprintf + %ls+ wstr

wprintf(L " %ls " ,wstr);

whodare@whodare:$ .
/ a. out
中文





使用了%ls,wprintf会将对应参数视为宽字符串wcs,这次终于没有搞错。因此wprintf会顺利的将给定的宽字符串写入标准输出流,最终正确显示"中文"


看完这4个例子,你对wprintf、printf和%ls 、%s的使用还有疑惑么?

四、小结

1。要清楚%ls和%s的意义在于指明所期待的参数是何种字符串,而printf和wprintf的区别在于所使用的是不同类型的stream

2。貌似在linux下输出“中文"的正确方法是 wprintf( "%ls\n",L"中文") ,而引文中作者在Windows成功操作的wprintf("%s\n", L"中文")在linux无法正确工作,至于为何wprintf这个标准库函数在两个系统下有不同表现,我是无心再向下深挖了,难道这又是VC一处不符合标准的地方?.......

3 。貌似还有一个%S,单独用于表示对应参数是宽字符串

谁能告诉我该问题的答案,不盛感激.......

参考:

1.http://blog.csdn.net/whitehack/archive/2011/01/03/6113908.aspx

2.http://blog.csdn.net/dawei_sun/archive/2008/12/17/3541351.aspx

3.http://hi.baidu.com/umu618/blog/item/77f3dac8e6ac5f117f3e6f0e.html

4.http://baike.baidu.com/view/849487.htm

5.http://www.360doc.com/content/08/1203/15/28217_2044833.shtml

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值