我们知道C语言用char数据类型来表示一个8位ANSI字符。默认情况下,在源代码中声明一个字符串时,C编译器会把字符串中的字符转换成8位char数据类型构成的一个数组。
Microsoft的C/C++编译器定义了一个内建的数据类型wchar_t,它表示一个16位的UnicodeUTF-16) 字符。因为早期版本的Microsoft编译器没有提供这个内建的数据类型,所以编译器只有在指定了/Zc:wchar_t编译器开关时,才会定义这个数据类型。默认情况下,在Microsoft Visual Studio 中新建一个C++项目时,这个编译器开关是指定的。建议始终指定这个编译器开关,这样才能借助于编译器天生就能理解的内建基元类型来更好地操纵Unicode字符。
注意 在编译器内建对wchar_t的支持之前,有一个C头文件定义了一个wchar_t数据类型:typedef unsigned short wchar_t;
声明Unicode字符和字符串的方法如下所示:
// 一个16位字符
wchar_t c = L'A';
// 一个数组,包含最多99个16 位字符以及一个16位的终止0
wchar_t szBuffer[100] = L"A String";
字符串之前的大写字母L通知编译器该字符串应当编译为一个Unicode字符串。当编译器将此字符串放入程序的数据段时,会使用UTF16来编码每个字符。在这个简单的例子中,在每个ASCII字符之间都用一个0来间隔。
为了与C语言稍微有一些隔离,Microsoft Windows团队希望定义自己的数据类型。于是,在Windows头文件WinNT.h中,定义了以下数据类型:
typedef char CHAR; // An 8-bit character
typedef wchar_t WCHAR; // A 16-bit character
除此之外,WinNT.h头文件还定义了一系列能为你提供大量便利的数据类型,可以用它处理字符和字符串指针:
// Pointer to 8-bit character(s)
typedef CHAR *PCHAR;
typedef CHAR *PSTR;
typedef CONST CHAR *PCSTR
// Pointer to 16-bit character(s)
typedef WCHAR *PWCHAR;
typedef WCHAR *PWSTR;
typedef CONST WCHAR *PCWSTR;
注意
仔细查看WinNT.h,会看到如下定义:
typedef __nullterminated WCHAR *NWPSTR, *LPWSTR, *PWSTR;
前缀__nullterminated是一个头部注解(header annotation),它描述一个类型如何作为函数的参数和返回值使用。在Visual Studio企业版中,可以在项目属性中设置代码分析(Code Analysis)选项。这样会把/analyze开关添加到编译器的命令行中。这样一来,假如你的代码调用函数的方式违反了头部注解所定义的语义,编译器就会检测到这类问题。注意,只有编译器的企业版才支持这个/analyze开关。为保证本书所提供的代码的可读性,所有header annotation都已被删除。要想更多地了解header annotation语言,请参考MSDN文档“HeaderAnnotations”,网址是http://msdn2.microsoft.com/En-US/library/aa383701.aspx。
在源代码中,具体使用哪种数据类型并不重要,但建议你尽量保持一致,以增强代码的可维护性。就我个人而言,作为Windows程序员,我会坚持使用Windows数据类型,因为这些数据类型与MSDN文档相符,有利于增强代码的可读性。
另外,你在写代码的时候,可以让它使用ANSI或Unicode字符/字符串都能通过编译。 WinNT.h定义了以下类型和宏:
#ifdef UNICODE
typedef WCHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST WCHAR *PCTSTR;
#define __TEXT(quote) quote // r_winnt
#define __TEXT(quote) L##quote
#else
typedef CHAR TCHAR, *PTCHAR, PTSTR;
typedef CONST CHAR *PCTSTR;
#define __TEXT(quote) quote
#endif
#define TEXT(quote) __TEXT(quote)
利用这些类型和宏(少数不太常用的没有在这里列出)来写代码,无论使字符,它都能通过编译。例如:
// 如果定义了UNICODE,就是一个16位字符;否则就是一个8位字符
TCHAR c = TEXT('A');
// 如果定义了UNICODE,就是由16位字符构成的一个数组;否则就是8位字符的一个数组
TCHAR szBuffer[100] = TEXT("A String");