首页 > 学院 > 开发设计 > 正文

宽字符和窄字符的一个坑

2019-11-10 17:23:23
字体:
来源:转载
供稿:网友

学习Windows编程的时候,遇到字符串处理会让人非常抓狂,当然问题的根本还是自己学艺不精,不过还是得吐槽一下,造成这一局面的原因是规则变化多端而又有点不可捉摸,这不,最近就掉到坑里面去了。

先看看下面的这段代码:

int main(int argn,char* argv[]){    char strA[]="ABC 简体中文";    wchar_t strW[]=L"ABC 简体中文";    PRintf("%s/n",strA);    wprintf(L"%s/n",strW);    return 0;}

猜猜看,输出是什么?在我的电脑上(程序使用VS2010编译通过,Windows 7操作系统,简体中文版)运行的结果是这样的:

image

第一个还好好地,怎么第二个会出现三个问号?

调试一下试试看,在return 0前面下断点,然后查看内存:

image

image

这个是strA在内存中的值:41 42 43 20 bc f2 cc e5 d6 d0 ce c4 00

而strW则是:41 00 42 00 43 00 20 00 80 7b 53 4f 2d 4e 87 65 00 00

首先,我们知道char类型占一个字节,而wchar_t则是占两个字节,前面的41,42,43,20就是分别’A’,’B’,’C’和’ ‘(空格),这里表明,宽字符采用的是Little-Endian方式存放两个字节的,接下来我们把重点都放在汉字上面。

在strA中,表示汉字“简体中文”数据为bc f2 cc e5 d6 d0 ce c4,而在strW则是80 7b 53 4f 2d 4e 87 65,差别很大,为什么是这样呢?

这其中涉及到了编码的问题。char类型中出现的汉字,采用的是GB2312的编码规则,查询该编码表,可以发现,“简”字的编码为BCF2,“体”为CCE5,“中”为D6D0,而“文”则为CEC4,这就是strA中中文的表示方式,但是在宽字符strW中,采用的编码则是Unicode编码,在Windows平台下Unicode编码值就是UTF-16编码值。查询“简体中文”四个汉字的编码,可以发现是7B80 4F53 4E2D 6587,由于计算机的架构为Little-Endian,需要把高低位字节互换,这也就是宽字符的表示形式。

根据网页上的说明(参考这里)C/C++标准只是声明wchar_t是一个可以表示字符集中的任意一个字符的足够宽的变量类型。wchar_t可以用任何encoding编码方式来存储这个字符,如ANSI、UCS-2或者UCS-4, 甚至是SCU-128,只不过我们通常是用unicode编码方式。wchar_t是与实现相关的。所以为了可移植性,我们不能假定wchar_t的编码方式,然后根据编码方式做一些相关性操作,我们只能理解它为一个足够宽的字符类型。

最后,我们还能顺便发现,wprintf函数在处理文本输出的时候,并不处理编码问题,而是直接按多字节字符顺序输出。

好,现在问题的原因找到了,那么该如何解决问题呢?

Windows当然不会没有想到这个问题,在Windows中,提供了如下两个函数:WideCharToMultiByte和MultiByteToWideChar,他们都位于头文件winnls.h中,分别是将宽字符转化为多字节和将多字节转化为宽字符。下面的例子直接给出了转化的代码,函数的具体使用方法可以翻阅MSDN。

int main(int argn,char* argv[]){    wchar_t strW[]=L"ABC 简体中文";    char* pW2A;    int t=0;    //第一次,确定需要的字节数    t=WideCharToMultiByte(CP_ACP,0,strW,-1,NULL,0,NULL,FALSE);    if(t!=0)    {        pW2A=(char*)malloc(t);//分配内存,然后运行第二次,注意参数区别        WideCharToMultiByte(CP_ACP,0,strW,-1,pW2A,t,NULL,FALSE);        printf("%s/n",pW2A);        free(pW2A);    }    return 0;}
这回显示就没有什么问题了,长舒一口气,暂时从坑里面爬出来了。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表