注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

信息 灵感 创新

I? =Information,Inspiration,Innovation

 
 
 

日志

 
 
关于我

we are 5. Mathematics, Computation, Programming, Engineering, and Making fun of life.

网易考拉推荐

宽字符和窄字符的一个坑  

2014-10-29 17:24:42|  分类: Windows编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

学习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;
}
这回显示就没有什么问题了,长舒一口气,暂时从坑里面爬出来了。
  评论这张
 
阅读(746)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016