Unicode编码与C语言宽字符


1.ASCII、ANSI、Unicode都是什么?

  • ASCII:
    American Standard Code for Information Interchange即美国信息交换标准代码,是一种非常常用的编码方式。标准ASCII码使用7位二进制数的组合来表示所有的大写和小写字母,数字0 到9、标点符号,以及在美式英语中使用的特殊控制字符,一共128个。标准ASCII码也叫做基础ASCII码。
    在这里插入图片描述
    但是欧洲的其他语言ASCII码无法完全表示,特别是一些注音符号,在法语中十分常见。那么ASCII码必须扩展。一种方式是使用8位而不是7位二进制数来表示字符,那么一共就会有256个字符可以表示。由80H到0FFH128个字符是由IBM制定的,用来表示一些框线、音标和其他语言的字母,这样的ASCII码被叫做扩展ASCII码

  • ANSI:
    为使计算机支持更多语言,通常使用 0x80~0xFFFF 范围的 2 个字节来表示 1 个字符。这种延伸的编码方式被称为ANSI。可以也把它当作ASCII码的一种扩展(0x00-0x7F既是标准ASCII码的范围,仍和ASCII码一样),16位长度让它可以表示出所有的字符,即使中日韩这样文字众多的语言也可以采用ANSI编码。但要注意,ANSI编码并不是指一种编码方式,不同国家的ANSI编码并不相同,例如中文的GB2312编码,日本的Shift_JIS编码。

  • Unicode
    如果每个国家都用自己的一套编码方式,那么字符编码冲突的问题会很麻烦,它们之间的交流也会很困难。所以一种全球统一的编码方式便孕育而出,那就是Unicode。正如字面意思,每个字符都被唯一的编码,能够表示所有符号。
    一般情况,Unicode需要使用2个字节即16位来表示一个字符。极少数需要4个字节。

2.为什么需要宽字符?

回想C语言中的char类型,大小是固定的一个字节。很明显如果C语言想要支持Unicode编码(或者其他的多字节编码),必须创造一种两个字节大小的类型。宽字符就这样诞生了,

“宽”字表示比char类型大,大小为两个字节。宽字符用wchar_t关键字定义。同理,一个字符串也要告诉编译器自己是否是Unicode编码。具体方法是在字符串前加上L表示Unicode编码。如下:

Wchar_t  wstr = L"abc";//注意L与字符串间不能有空格

3.C语言如何处理宽字符?

增加了宽字符对C语言的影响可是很大的,并不仅仅是增加了一个类型。而是涉及到字符串的函数需要重写。例如:对wchar_t类型的字符串使用strlen()函数返回值会是1,而不是字符串的长度。

这与C语言中的字符串的储存方式有关,标准的方式是在字符串的末尾加一个“\0”作为结束符,识别到了这个结束符就代表字符串结束了。但对宽字符串可不是这样的,例如字符串“AA”在宽字符下表示为0X0061、 0X0061,又由于Windows的小端字节序(字节的低位在左,高位在右,例如:0X123456在内存中便是56 34 12),实际在内存中的储存是61 00 61 00,这个00放在了61后面,如果不重写有关字符串的函数,那么会把它当作结束符从而识别出长度为1的字符串。

幸运的是,重写的工作已经被完成了。涉及字符的函数一般都有两份分别对应char 和wchar_t。甚至为了方便编程,微软提供了TCHAR.H包,里面通过条件编译可以自动选择对应的处理char或者wchar_t的函数。

例如:MessageBox函数,它的功能是弹出一个对话框,显示文字和按钮。MessageBox其实有两个版本,一个是MessageBoxA用来处理char,另一个是MessageBoxW用来处理wchar_t。当你调用MessageBox时,如果你定义了UNICODE宏时,MessageBox就等价于MessageBoxW;如果没有定义则等价于MessageBoxA。

WINUSERAPI int WINAPI MessageBoxA(
 
HWND hWnd,
 
LPCSTR lpText,
 
LPCSTR lpCaption,
 
UINT uType);
 
 
WINUSERAPI int WINAPI MessageBoxW(
 
HWND hWnd,
 
LPCWSTR lpText,
 
LPCWSTR lpCaption,
 
UINT uType);
 
 
#ifdef UNICODE
 
#define MessageBox MessageBoxW//如果启用Unicode库,就用MessageBoxW
 
#else
 
#define MessageBox MessageBoxA//否则,就用MessageBoxA
 
#endif

这样将一份为ASCII编码准备的代码修改为Unicode版本便变得简单了很多,似乎只要定义UNICODE宏。

但是别忘了宽字符串前必不可少的L,如何才能避免去添加或者删除这个L呢?还是宏。_TEXT()、TEXT()、_T()这几个宏都是等价的,它们会根据是否启用了Unicode来自动决定是否为字符串加上L。这几个和MessageBox一样,也是通过条件编译实现的。
例如:这是TEXT()的定义

 #define TEXT(quote) __TEXT(quote)   
    
 #ifdef  UNICODE                       
 #define __TEXT(quote) L##quote        
 #else   /* UNICODE */                 
 #define __TEXT(quote) quote           
 #endif /* UNICODE */  

有了这个,只要将字符串放进TEXT()宏内,在启用或禁用Unicode后原来的代码就不用修改了。

4.Windows中的字符串函数

lstrlen 返回字符串中字符的个数(如果操作系统定义了UINCODE,则表示宽字符,如果未定义,则表示ANSI字符)
类似的还有
lstrlen
lstrcpy
lstrcpyn
lstrcat
lstrcmp
lstrcmpi

常用函数 wsprintf 是sprintf的Unicode版本

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值