宽字符集和Unicode
2.1
Unicode扩展自ASCII字符集。在严格的ASCII中,每个字符用7位表示,或者计算机上普遍使用的每字符有8位宽;而Unicode使用全16位字符集。这使得Unicode能够表示世界上所有的书写语言中可能用于计算机通讯的字符、象形文字和其它符号。但ASCI仍I是计算机中最具支配地位的标准。
美国信息交换标准码(ASCII:American Standard Code for Information Interchange )
双字节字符集(DBCS:double-byte character set)
Unicode
明白Unicode和DBCS之间的区别很重要。
(1)Unicode使用(特别在C 程序设计语言环境里)「宽字符集」。「Unicode中的每个字符都是16位宽而不是8位宽。」在Unicode中,没有单单使用8位数值的意义存在。相比之下,在双字节字符集中我们仍然处理8位数值。有些字节自身定义字符,而某些字节则显示需要和另一个字节共同定义一个字符。
(2)处理DBCS字符串非常杂乱,但是处理Unicode文字则像处理有秩序的文字。
(3)Unicode的最大好处是这里只有一个字符集
Unicode有缺点
(1)Unicode字符串占用的内存是ASCII字符串的两倍。(然而压缩文件有助于极大地减少文件所占的磁盘空间。)
(2)人们相对来说还不习惯使用Unicode。
「美国国家标准程序设计语言-C 」(也称作「ANSI C」)通过一个称作「宽字符」的概念来支持用多个字节代表一字符的字符集。这些宽字符与常用的字符完美地共存。
多字节字符集主要影响C 语言程序执行时期链接库函数。相比之下,宽字符比正常字符宽,而且会引起一些编译问题。
2.2 宽字符和C语言
Unicode或者宽字元都没有改变char资料型态在C中的含义。char继续表示1个位元组的储存空间, sizeof (char) 继续返回1。
C中的宽字元基於wchar_t资料型态,它在几个表头档案包括WCHAR.H中都有定义,像这样:
typedef unsigned short wchar_t ;
因此,wchar_t资料型态与无符号短整数型态相同,都是16位元宽。
要定义包含一个宽字元的变数,可使用下面的语句:
wchar_t c = 'A' ; //wchar_t c = L'A' ;
变数c是一个双位元组值0x0041,是Unicode表示的字母A。
还可定义指向宽字串的指标:
wchar_t * p = L"Hello!" ;
注意紧接在第一个引号前面的大写字母L(代表「long」)。这将告诉编译器该字串按宽字元保存——即每个字元占用2个位元组。
static wchar_t a[] = L"Hello!" ;
该字串也需要14个位元组的储存空间,sizeof (a) 将返回14。
char * pc = "Hello!" ;
iLength = strlen (pc) ; //iLength=6
wchar_t * pw = L"Hello!" ;
iLength = strlen (pw) ; //error or warnning:function' : incompatible types - from 'unsigned short *' to 'const char *'
strlen函式的宽字元版是wcslen(wide-character string length:宽字串长度),并且在STRING.H(其中也说明了strlen)和WCHAR.H中均有说明。
strlen函式说明如下:
size_t __cdecl strlen (const char *) ;
而wcslen函式则说明如下:
size_t __cdecl wcslen (const wchar_t *) ;
wchar_t * pw = L"Hello!" ;
iLength = wcslen (pw) ; //ok, iLength=6
请记住,改成宽位字符后,字符串的字符长度不改变仍是6,只是存储的字节长度改变成原先的2倍。
2.3宽字符和Windows
Windows NT从底层支持Unicode。Windows NT可执行为ASCII、Unicode或者ASCII和Unicode混合编写的程式。即,Windows NT支持不同的字符串的API函数调用来实现。
一个Windows程序包括表头文件WINDOWS.H。该文件包括许多其它头文件,包括WINDEF.H,该文件中有许多在Windows中使用的基本数据类型的定义,而且它本身也包括WINNT.H。WINNT.H处理基本的Unicode支持。
WINNT.H的前面包含C 的表头文件CTYPE.H,这是C 的众多表头文件之一,包括wchar_t的定义。WINNT.H定义了新的数据型态,称作CHAR 和WCHAR:
typedef char CHAR ;
typedef wchar_t WCHAR ; // wc
当您需要定义8位字符或者16位字符时,推荐您在Windows程序中使用的数据型态是CHAR 和WCHAR。WCHAR定义后面的注释是匈牙利标记法的建议:一个基于WCHAR数据型态的变量可在前面附加上字母wc以说明一个宽字符。
无论何时在程序中使用其它表头文件时,都应在所有其它表头文件之前包含WINDOWS.H。
WINNT.H表头文件还定义了一个宏,该宏将L 添加到字符串的第一个引号前。如果定义了UNICODE标识符,则一个称作 __TEXT 的宏定义如下:
#define __TEXT(quote) L##quote
如果没有定义标识符UNICODE,则像这样定义__TEXT 宏:
#define __TEXT(quote) quote
此外, TEXT 宏可这样定义:
#define TEXT(quote) __TEXT(quote)
这些定义可使您在同一程序中混合使用ASCII和Unicode字符串,或者编写一个可被ASCII或Unicode编译的程序。
Windows的字符串函数
下面是Windows定义的一组字符串函数,这些函数用来计算字符串长度、复制字符串、连接字符串和比较字符串:
ILength = lstrlen (pString) ;
pString = lstrcpy (pString1, pString2) ;
pString = lstrcpyn (pString1, pString2, iCount) ;
pString = lstrcat (pString1, pString2) ;
iComp = lstrcmp (pString1, pString2) ;
iComp = lstrcmpi (pString1, pString2) ;
这些函数与C 链接库中对应的函数功能相同。如果定义了UNICODE标识符,那么这些函数将接受宽字符串,否则只接受常规字符串。
在Windows中使用printf
坏消息:在Windows程序中不能使用printf。虽然Windows程序中可以使用大多数C 的执行时期链接库-实际上,许多程序写作者更愿意使用C 内存管理和文件I/O函数而不是Windows中等效的函数-Windows对标准输入和标准输出没有概念。在Windows程序中可使用fprintf ,而不是printf。
好消息,那就是仍然可以使用sprintf 及sprintf 系列中的其它函数来显示文字。这些函数除了将内容格式化输出到函数第一个参数所提供的字符串缓冲区以外,其功能与printfI 相同。然后便可对该字符串进行操作(例如将其传给MessageBox)。
printf ("The sum of %i and %i is %i", 5, 3, 5+3) ;
的功能相同于
char szBuffer [100] ;
sprintf (szBuffer, "The sum of %i and %i is %i", 5, 3, 5+3) ;
puts (szBuffer) ;
在Windows中,使用MessageBox显示结果优于puts 。
#include
#include
#include
int CDECL MessageBoxPrintf (TCHAR * szCaption, TCHAR * szFormat,...)
{
TCHAR szBuffer [1024] ;
va_list pArgList ;
// The va_start macro (defined in STDARG.H) is usually equivalent to:
// pArgList = (char *) &szFormat + sizeof (szFormat) ;
va_start (pArgList, szFormat) ;
// The last argument to wvsprintf points to the arguments
_vsntprintf ( szBuffer, sizeof (szBuffer) / sizeof (TCHAR),
szFormat, pArgList) ;
// The va_end macro just zeroes out pArgList for no good reason
va_end (pArgList) ;
return MessageBox (NULL, szBuffer, szCaption, 0) ;
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
int cxScreen, cyScreen ;
cxScreen = GetSystemMetrics (SM_CXSCREEN) ;
cyScreen = GetSystemMetrics (SM_CYSCREEN) ;
MessageBoxPrintf ( TEXT ("ScrnSize"), TEXT ("The screen is %i pixels wide by %i pixels high."),
cxScreen, cyScreen) ;
return 0 ;
}
经由从GetSystemMetrics函数得到的信息,该程序以图素为单位显示了视讯显示的宽度和高度。GetSystemMetrics是一个能用来获得Windows中不同对象的
尺寸信息的函数。