宽字符

Unicode

宽字符有很多种,Unicode只 是宽字符编码的一种实现,每个字符用 16位 表示。

Unicode的产生是为了解决许多8位无法标识的东西。

 

ASCII

这是世界上流行的编码,每个字符用 7位 表示。但是这套编码不能表示一些其他国家的字符,可以说这套编码是为美国设计的。
C语言的宽字符是基于 wchar_t 数据类型的。这个数据类型被定义在多个头文件中,包括 WCHAR.H
   typedef  unsigned short wchar_t;

所以 wchar_t  数据类型和一个无符号整型一样,都是 16位 宽。

可以这样定义一个包含单个宽字符的变量

wchar_t c = 'A' ;

也可以这样定义:
wchar_t c = L'A' ;       //但这通常是不需要的。

变量 c 是一个 2 byte 的值0x0041,这是Unicode中字母A的代表。它在内存中的存储是按照高位在后,低位在前存储的。

所以在内存中是这样,0x41,0x00。
可以这样定义一个已初始化的指向宽字符串的指针:

 wchar_t *p = L"Hello!";

  注意:大写字母 L 紧接着左引号。这向编译器表明这个字符串将用宽字符存储,也就是说每个字符 2 byte。
 
   这个字符串一共 14 byte,因为字符串结尾需要加 0 。
   指针变量 p 需要 4 byte的存储空间,因为在汇编里 cs:ip 表示代码执行的指针。cs : 段位移    ip : 偏移地址。

 

宽字符库函数
   大家都知道     char *pc = "Hello!";               iLength = strlen(pc);                   iLength = 6

             那么    wchar_t *pw = L"Hello!";       iLength = strlen(pw);                  iLength = ?

    此时编译的话编译器会发出警告,意思是strlen函数在被定义是为接收一个指向char的指针,
    但这里收到的是一个指向无符号短整型的指针。但仍可以运行。 但 iLength =1  这是为什么呢?
   因为这些字符串数据是这样存储在内存中的   48 00 65 00 6c 00 6F 00 21 00
   strlen函数仍试图找字符串的长度,计算第一个字节作为字符,但然后认为第二个字节 0 为字符串的结尾。所以长度为 1 。
 
  因此对于宽字符的数据处理也引入了专门的库函数。

  宽字符版本的strlen函数被称为 wcslen("string"),并定义在STRING.H 和 WCHAR.H 中。

   在介绍使用之前,先来介绍下面两个数据类型:   CHAR              WCHAR

    在 WINNT.H 中定义了:

                        typedef   char   CHAR;                               用来定义 8位 的字符

                       typedef   wchar_t    WCHAR;                     用来定义 16位 的字符

    当然其中也定义了字符指针:
     这些都是 8位 字符串指针                                    指每次指针移动偏移 8位

                       typedef  CHAR * PCHAR,* LPCH,* NPSTR, * PSTR;

                       typedef  CONST CHAR * LPCCH, * PCCH, * LPCSTR, * PCSTR;

这里的 PCHAR,LPCH,NPSTR,PSTR 都是CHAR * 的别名,以后定义一个指针就可以直接用别名了。

     例如 :CHAR *P     和   PCHAR P     是同一个意思,懂了吧
     也有 16位 的字符串指针                                       指每次指针移动偏移 16 位

                      typedef  WCHAR *PWCHAR,*LPWCH, *PWCH, *NWPSTR, *LPWSTR, *PWSTR;

                      typedef  CONST WCHAR * LPCWCH, * PCWCH, * LPCWSTR, * PCWSTR;

     另外,前缀 N 和 L 分别是表示"近"(near),和"远"(long),指的是 16位 Windows系统中的两种大小不同的指针

    不过在win32中near,和long指针没有区别,所以不必管它。
 
那么如何使用同一个函数名来实现不同的功能呢?
  在包含头文件 TCHAR.H 的情况下,举个例子:如果一个命名为_UNICODE的标识符被定义了,那么就实现处理宽字符串的功能,
  否则就仍是处理单字节字符的字符串。
#ifdef  UNICODE                   
typedef WCHAR TCHAR, *PTCHAR ;
typedef LPWSTR LPTCH, PTCH, PTSTR, LPTSTR ;
typedef LPCWSTR LPCTSTR ;
#else 
typedef char TCHAR, *PTCHAR ;
typedef LPSTR LPTCH, PTCH, PTSTR, LPTSTR ;
typedef LPCSTR LPCTSTR ;
#endif

同时用来选择字符处理函数,例如WINUSER.H中:

#ifdef UNICODE
#define MessageBox  MessageBoxW
#else
#define MessageBox  MessageBoxA
#endif 

这 样,我们只用一种类型(比如TCHAR)和一组函数(比如MessageBox)就方便地可以处理两种编码的程序,

而不用去条件判断应该用char还是 wchar_t,

应该用MessageBoxA还是MessageBoxW。这些细节Windows.h等头文件中已经为我们考虑了,

我们要做的只是在需要用Unicode时定义两个符号。

 

另外提醒一下:

                  _UNICODE 是让 C 函数使用 unicode
                    UNICODE  是让 API 使用 unicode

 

posted @ 2018-07-11 07:30  M-Anonymous  阅读(2849)  评论(0编辑  收藏  举报