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

信息 灵感 创新

I? =Information,Inspiration,Innovation

 
 
 

日志

 
 
关于我

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

网易考拉推荐

字符和宽字符  

2014-06-25 14:56:20|  分类: Windows编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

在开始使用C语言时,对于字符的理解就到char类型,占1个字节,而字符串,则是以字符’\0’结尾的字符数组,通常在使用英文字母的国家,ASCII码就够用了,因此char类型就能表达所有的大小写字母和数字,以及其他标点符号等。但是字符的概念不仅限于ASCII表中所提供的,想想世界上其他的国度,例如你看到的这篇文章,使用的就是简体中文,还有其他如日文、韩文/朝鲜文,阿拉伯文字等,这都都是字符,但是却不能使用ASCII所表达,因为一个字节所能表达的最多字符也就是256个(这还是扩展ASCII码所能表达的,最开始ASCII码仅128个)。于是使用两个字节的UNICODE应时而生了,由于使用了两个字节,理论上能表达的字符将达到216个,也就是65536个字符了,对于我们所处的星球,已经能够包含所有语言中出现的字符了,而且,Unicode不仅仅是字符,还有其他各种图形符号,例如?,?,等。

Unicode的好处我就不一一列举了,虽然我觉得如果一开始的时候,所有的字符编码都采用Unicode的话,会省去很多的麻烦,但是必须承认,ASCII码还是有两点比Unicode强:

1. 处理速度快一些,而且可以无视Big-Endian和Little-Endian;

2. 所占空间小。

因此,针对英语国家的编程中,使用ASCII码就足够了,基本上没有Unicode码什么事了,但是如果需要国际化,Unicode就是不二的选择,所以很有必要研究一下这两种字符之间的联系和区别。

C/C++语言中提供了wchar_t的类型表示宽字符,与char同ASCII码对应类似,wchar_t与Unicode对应。

1.字符之间的转换

下面在提到字符的时候,指代的都是char,宽字符则是wchar_t。

1.1 字符转宽字符

位于头文件stdlib下的mbtowc(multi-byte to wide char)实现将多字节字符(ASCII码)转化为宽字符(Unicode码),如下:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    printf("size of char: %d, size of wchar_t: %d\n",sizeof(char),sizeof(wchar_t));
    char ac;
    wchar_t uc;
    ac='A';
    uc=L'x';
    wprintf(L"%c\n",uc);
    int t=mbtowc(&uc,&ac,sizeof(ac));
    wprintf(L"%c\n",uc);
    return 0;
}
这个程序很简单,先显示两种类型所占的字节数,然后输出一个x,最后输出一个A,请注意宽字符格式化的前缀“L”,告诉编译器强制使用宽字符。可以看看内存中的内容:
image
可以看到,uc确实占据了两个字节(cc前面的两个)。

2. 宽字符转字符

对,你猜的没错,stdlib.h下也提供了一个叫做wctomb的函数,实现将宽字符转化为多字节字符。看下面的示例:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    char ac;
    wchar_t uc;
    int t;
    uc=L'T';
    t=wctomb(&ac,uc);
    printf("t=%d,%c\n",t,ac);
    uc=L'他';
    t=wctomb(&ac,uc);
    printf("t=%d,%c\n",t,ac);
    return 0;
}
这段示例代码的运行如下:
image
可以看到,第二次转换失败后,返回值为-1,不能输出字符。检查一下内存中的数据:
image
这个例子告诉我们,虽然wctomb可能执行失败(检查返回值),但是仍旧会修改目的字符的值,没有对应的值,则直接将其变为'\0'。

2. 字符串的转换

2.1 字符串转宽字符串

前面提到的字符转宽字符函数mbtowc,与之对应的数组版本则是mbstowcs,函数将一个字符数组转化为宽字符数组。函数原型如下:

size_t mbstowcs(wchar_t* dest, const char* src, size_t max);
其中scr就是待转化的字符串,而dest则是目标字符串,max指定了待转化字符的个数,注意,如果在转化过程中没有达到max个转化字符,而又碰到了’\0’,则转化结束,dest中包含了’\0’的宽字符版本(0x0000),如果转化字符个数达到了max而一直没有碰到’\0’,则转化也会结束,但是最终的dest中并不包含’\0’的宽字符版本。
函数的返回值,如果转化成功,则返回值是dest中不包括’\00’的字符个数,可能是下列值之一:(a)没有碰到’\0’,返回值等于max。(b)碰到’\0’,则返回值应该等于strlen(scr)。
如果碰到不能转换的值,则返回-1。
测试程序:
#include <stdio.h>
#include <stdlib.h>
int main()
{
    char as[]="It's good to see you again.";
    wchar_t us[100]=L"";
    int t;
    t=mbstowcs(us,as,100);
    wprintf(L"t=%d,us=%s",t,us);
    return 0;
}
运行后检查内存,确实转化过来:
image

2.2 宽字符串转字符串

你又猜对了,这回的主角是wcstombs,该函数将宽字符串转化为字符串。函数的使用方式同前面类似,但是有一点需要注意的是,字符串转宽字符串通常都是成功的,因为我们可以将ASCII看作是Unicode的子集,但是反过来,将宽字符串转化为字符串,并不一定能成功,看下面的例子:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    char as[100]="";
    wchar_t us[]=L"Nice to meet you. 很高兴见到你, me too.";
    int t;
    t=wcstombs(as,us,100);
    printf("t=%d,as=%s",t,as);
    return 0;
}
运行效果如下:
image
检查内存为:
image

可以看到,返回值为-1,表明转换失败,但是目标字符串还是被修改,不能被转换的部分被裁剪掉了。这种结果可能是你需要的,也可能不是,使用的时候尤其注意。

  评论这张
 
阅读(360)| 评论(0)
推荐 转载

历史上的今天

评论

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

页脚

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