开始使用Unicode,告别ASCII

以前看windows编程上面的书籍总会涉及到Unicode编码,只是由于平时写些小程序使用char,string也不会出什么问题,所以一直也没在意。而随着程序的增大,字符上的问题开始显现出来,特别是有中文字符的时候,有时候简直被这种小问题弄得发疯。

这几天在看windows核心编程,受其感召,加上以前的教训,因此从现在开始准备都使用宽字符编码。(啊~终于不用每次设置VS2008中的字符集为多字符集了呀~)

 

好了,丢掉char,换上wchar_t,什么变量函数都加个w,呵呵

 

可是,问题来了。

 

试一下这个代码:

 

#include<iostream>

using namespace std;

int main()

{

     wchar_t wc[]=L"你好啊~wchar_t";

     wcout<<wc<<endl;

     return 0;

}

 

结果非预想中的那么好,郁闷了半天,网上查了好长时间,有的是使用函数转换为char型,可是这有违初衷啊,而且效率也低。

后来发现有个很重要但从来都没有用过的东西:locale

这实在是个好东西啊,有了它,wchar_t 就可以像char一样简单了。

关于locale的使用方法不赘述,自己查资料。

 

附:

前段时间看了一下C/C++中的Locale和Wide Character的使用,才知道C/C++标准中已经包含了处理非ASCII码字符的方法,而一些实现(比如gcc和VC)已经提供了很好的支持。这里把学到的知识总结一下,希望会对大家有用。


处理非ASCII码字符

当需要处理非ASCII码的字符时, 程序的编写就需要涉及到两个概念 -- Locale和 wide character, C/C++使用Locale来表示当前程序运行的环境, 其中包括字符编码的信息. 而wide character则用于字符的内部存储和处理.

1. wchar_t类型和multibyte charater
    C/C++ 中提供了wchar_t类型来存储wide character, 但其长度和字符的编码方式是由实现决定的, 在GCC中, wchar_t占4个字节, 而在VC中, 则占2个字节.
   
    因为兼容性和空间节省等方面的考虑, 一般的字符存储并非使用 wide character, 而是仍然采用面向字节的方式存储, 不同的是, 字符的表示可能会使用多个字节, 这被称为multibyte character, 比如说UTF-8编码. 因此, 当程序中指定了wide character常量, 或者读入/写出wide character时, 就需要涉及到wide character和multibyte character之间的转换. C/C++中提供了mbtowc, wctomb, mbtowcs, wcstomb这样的函数来完成转换操作.
   
wchar_t常量

当需要使用wchar_t字符或字符串常量时, 使用L前缀. 比如说下面的例子:

wchar_t ch1 = L'字';
wchar_t ch2 = L'符';
wchar_t *wstr = L"宽字符串";
   
    前面提到了, 源代码是按照multibyte character来存储的(用户机器的编码方式), 所以实际上这样的宽字符串在源文件中是multibyte character字符. 所以, 当编译源程序时, 编译器需要根据机器的Locale信息来获取源代码的编码方式, 并根据此将multibyte character转换为wide character.也就是说, 当使用wide character常量时, 程序员不需要考虑从multibyte character到wide character的转换, 编译器会帮助你完成这样的工作, 当然, 前提是编译器可以正确识别源代码的编码方式.
   
C语言中的wide character输入输出

C提供的所有的输入输出函数都提供了相应的wchar_t版本, 当使用wchar_t版本的输出输出函数时, 函数会根据当前的locale信息将读入的multibyte character转换为wide character而返回给用户.程序员需要做的就是设定正确的locale和调用正确版本的函数.C语言提供了setlocale()函数来完成locale的设定, 这样的设定是全局性的, 当通过setlocale()设定相应的locale之后,所有的wide character版本的函数都会受到影响, 没有办法同时为不同的输入输出函数设定不同locale, 如果需要在程序中处理多个locale, 那么程序员需要在程序中的不同地方调用setlocale()设定不同的locale.
   
当然,在大多数情况下, 程序员都只需要在程序开始设定一次locale, 然后就不需要更改locale设定.比如说下面的例子:
   
#include<stdio.h>
#include<wchar.h>
#include<locale.h>

int main()
{  
   if(setlocale(LC_ALL, "") == NULL){
fprintf(STDERR,"setlocale error/n";
   }

   wchar_t *ws = L"中文/Chinese";
   wprintf(L"%ls/n", ws);
   return 0;
}
   
setlocale的第一个参数为需要设置的locale参数的名字,而第二个参数为该locale参数的值,这是一个由实现决定的(implementation-defined)字符串值, 如果第二个参数为空字符串(比如例子中的方式), 那么locale会被按照系统的locale值来设定, 这在大多数情况下都是可行的. 当然, 程序员也可以显示的指定locale值,比如:
   
setlocale(LC_ALL, "zh_CN.UTF-8");  //implementation-defined locale value.
   
关于locale和wide character的更多细节, 请查看C语言的相关参考手册.
   

C++中的wide character

C++中的locale实现和C语言最大的不同在于, 在C++中, 不仅可以设定全局的locale值, 同时还可以为每一个输入输出流指定自己的loale, 这样就让处理多种locale的时候更加方便了.在C++中, 程序员可以通过static locale::global(const locale&)函数来设定全局的locale, 比如说下面的例子:
   
#include<iostream>
#include<locale>

using namespace std;

int main()
{
   locale::global(locale(""));
   wstring str = L"中文/Chinese";
   wcout << str << endl;
   return 0;
}    
   
locale("")将按照系统locale设定来构造相应的locale对象.
我们还可以为某个特定的输入输出流指定locale值, 该操作用std::ios_base::imbue(const locale&)来完成.当针对某个输入输出流调用该操作更改其locale值之后,该对象的输入输出操作将按照设定的locale来完成.但是需要注意的是,在GCC中, 使用这样的方法改变wcout, wcin, werr的locale似乎不起作用, 请看下面的一段话:
   
That said, in the area of locale vs streams, a lot is implementation defined: our implementation, by defaults has the predefined
streams (cin, cout, wcin, wcout...) synced with stdio. That means that certainly the wchar_t versions are sensible to the global locale,
 because they use directly the underlying wchar_t C library functions to achieve that sync. You can change that behavior (thus
 loosing the sync) by calling sync_with_stdio(false) before any I / O.

也就是说, 如果需要单独改变wcout, wcin , werr的locale, 那么需要在进行任何I/O之前调用
static std::ios_base::sync_with_studio(false)来解除这些流和stdio的同步关系.
   
下面的例子示例了如何为某一个流单独指定某个特定的locale:
#include<iostream>
#include<locale>
#include<fstream>

using namespace std;

int main()
{
   basic_fstream<wchar_t> output("locale.txt");  
   output.imbue(locale(""));
   wstring str = L"中文/Chinese";
   output << str << endl;
   return 0;
}  

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值