编码的发展历史:

1.ASCII

美国信息交换标准码(ASCII:American Standard Code for Information Interchange)起始于50年代后期,最后完成于1967年。综合考虑不采用字符替换以及成本问题,采用7位,

Windows字符编码_字符编码

2.扩展ASCII

因为遵循了ANSI草案和ISO标准,纯Windows字符集被称作「ANSI字符集」。ANSI草案和ISO标准最终成为ANSI/ISO 8859-1-1987,即「American National Standard for Information Processing-8-Bit Single-Byte Coded Graphic Character Sets-Part 1: Latin Alphabet No 1」,通常也简写为「Latin 1」。其中采用了8位进行存储,增加了一些西欧语言的字符及符号。空方框表示该位置未定义字符。

Windows字符编码_Windows_02

3.双字节字符集

中国、日本和韩国的象形文字符号有大约21,000个。为了容纳这些语言,早期采用了双字节字符集(DBCS:double-byte character set)。

DBCS从256代码开始,就像ASCII一样。与任何行为良好的代码页一样,最初的128个代码是ASCII。然而,较高的128个代码中的某些总是跟随着第二个字节。这两个字节一起(称作首字节和跟随字节)定义一个字符,通常是一个复杂的象形文字。

虽然中文、日文和韩文共享一些相同的象形文字,但显然这三种语言是不同的,而且经常是同一个象形文字在三种不同的语言中代表三件不同的事。Windows支持四个不同的双字节字符集:代码页932(日文)、936(简体中文)、949(韩语)和950(繁体汉字)。只有为这些国家(地区)生产的Windows版本才支持DBCS。

 

双字符集问题并不是说字符由两个字节代表。问题在于一些字符(特别是ASCII字符)由1个字节表示。这会引起附加的程序设计问题。例如,字符串中的字符数不能由字符串的字节数决定。必须剖析字符串来决定其长度,而且必须检查每个字节以确定它是否为双字节字符的首字节。如果有一个指向DBCS字符串中间的指针,那么该字符串前一个字符的地址是什么呢?惯用的解决方案是从开始的指针分析该字符串!

4.Unicode

Unicode是统一的16位系统,这样就允许表示65,536个字符。

处理DBCS字符串非常杂乱,但是处理Unicode文字则像处理有秩序的文字。您也许会高兴地知道前128个Unicode字符(16位代码从0x0000到0x007F)就是ASCII字符,而接下来的128个Unicode字符(代码从0x0080到0x00FF)是ISO 8859-1对ASCII的扩展。Unicode中不同部分的字符都同样基于现有的标准。这是为了便于转换。希腊字母表使用从0x0370到0x03FF的代码,斯拉夫语使用从0x0400到0x04FF的代码,美国使用从0x0530到0x058F的代码,希伯来语使用从0x0590到0x05FF的代码。中国、日本和韩国的象形文字(总称为CJK)占用了从0x3000到0x9FFF的代码。

字符在C中的处理:

普通的char变量为1字节存储,char*为4字节。

 

C中的宽字符基于wchar_t数据型态,它在几个表头文件包括WCHAR.H中都有定义,像这样:

 


  1. typedef unsigned short wchar_t ; 

 

 

因此,wchar_t数据型态与无符号短整数型态相同,都是16位宽。

要定义包含一个宽字符的变量,可使用下面的语句:


        
  1. wchar_t c = 'A' ; 

变量c是一个双字节值0x0041,是Unicode表示的字母A。(然而,因为Intel微处理器从最小的字节开始储存多字节数值,该字节实际上是以0x41、0x00的顺序保存在内存中。如果检查Unicode文字的计算机储存应注意这一点。)

您还可定义指向宽字符串的指针:


        
  1. wchar_t * p = L"Hello!" ; 

注意紧接在第一个引号前面的大写字母L(代表「long」)。这将告诉编译器该字符串按宽字符保存-即每个字符占用2个字节。通常,指针变量p要占用4个字节,而字符串变量需要14个字节-每个字符需要2个字节,末尾的0还需要2个字节。

同样,您还可以用下面的语句定义宽字符数组:


        
  1. static wchar_t a[] = L"Hello!" ; 

该字符串也需要14个字节的储存空间,sizeof (a) 将返回14。索引数组a可得到单独的字符。a[1] 的值是宽字符「e」,或者0x0065。

 

strlen等的问题:

strlen遇到0识别字符串结束,而unicode中的字母一般为00XX保存,在intel处理器中小端存储为XX 00,则会直接识别为字符串结束。

所以对应采用wcslen

为了兼容这两种字符编码,就出现了tchar.h

_tcslen

TCHAR

__T(x) _T(x) _TEXT(x) 

windows.h及其所包含的的头文件中(WINNT.H):

 


  1. typedef char CHAR ;         
  2. typedef wchar_t WCHAR ;    // wc         
  3.  
  4. typedef CHAR * PCHAR, * LPCH, * PCH, * NPSTR, * LPSTR, * PSTR ;         
  5. typedef CONST CHAR * LPCCH, * PCCH, * LPCSTR, * PCSTR ;       
  6.  
  7. typedef WCHAR * PWCHAR, * LPWCH, * PWCH, * NWPSTR, * LPWSTR, * PWSTR ;         
  8. typedef CONST WCHAR * LPCWCH, * PCWCH, * LPCWSTR, * PCWSTR ;      

WINNT.H将TCHAR定义为一般的字符类型。如果定义了标识符UNICODE(没有底线),则TCHAR和指向TCHAR的指标就分别定义为WCHAR和指向WCHAR的指标;如果没有定义标识符UNICODE,则TCHAR和指向TCHAR的指标就分别定义为char和指向char的指标:

 

  1. #ifdef  UNICODE  
  2. typedef WCHAR TCHAR, * PTCHAR ; 
  3. typedef LPWSTR LPTCH, PTCH, PTSTRLPTSTR ;  
  4. typedef LPCWSTR LPCTSTR ;       
  5. #else 
  6. typedef char TCHAR, * PTCHAR ;   
  7. typedef LPSTR LPTCH, PTCH, PTSTRLPTSTR ;  
  8. typedef LPCSTR LPCTSTR ;    
  9. #endif