第二章 Unicode简介
unicode实际上是对ASCII字符编码的一个扩展,Unicode用的是16位的字符编码而标准的ASCII用的是7位的字符编码。7位的标准ASCII能显示128个字符或符号,当然,就算是8位的最多也只能显示256个字符或符号。显然这256个字符远远满足不了我们的需要(用英语等的除外),你可以想象一下中国字有多少个,总不能把所用的汉字都用拼音写出来吧。。。Unicode能表示多少个字符或符号呢?你自己算一下!65,536个!这样在计算机通信中,世界上所有书面语的字母,象形文字和其他符号度可以用Unicode来表示。
2.1 字符集简史
这个不说了如有兴趣自行百度之。。。
2.2 宽字符和C语言
大多数用C语言的都有这样的一个共识,那就是一个字符的宽度和一个字节的长度相同的,这是一个无可争辩的事实之一。 可能只有少数的程序员意识到了这一点:ASCI C,通过一种叫“宽字符”的概念来支持用多个字节代表一个字符的字符集。
2.2.1~2.2.2 char数据类型
为了进一步了解C语言如何处理宽字符,我们先来看看正常字符的定义。
下面的声明定义和初始化一个包含当以字符的变量:
char c = 'A';变量c需要一个字节的存储空间而且会用16进制值0x41来初始化,也就是ASCII 字母A的符号。
char *p;
可以如下初始化一个字符串指针:
char *p = "hello!";指针变量p需要4个字节的存储空间(我们用的是32位的windows)。字符串存储在内存中并使用7个字节的存储空间——其中6个字节存储字符串而另外一个字节存储表示字符结束的'\0'。
char a[10];这种情况下数组a将会获得10个字节的存储空间。如果数组是全局变量我们可以在函数外部这样来初始化一个字符数组:
char a[] = "hello!";如果是函数内的一个局部变量只需在函数内部来初始化这个字符数组。(即把这段代码放入函数内部)。如果我们定义的是一个静态变量,只需在对应的初始化代码前面加上关键字static:
static char a[] = "hello!";无论是哪种情况字符串始终被存储在静态内存中,并有一个'\0'加载最后,所以也需要7个字节的存储空间。
2.2.2 更宽的字符
使用Unicode或者是宽字符并不会改变C语言中的字符数据类型。也就是说char数据类型就是1个字节。C语言中的宽字符是基于wchar_t数据类型的。这个数据类型被定义在多个头文件中,包括WCHAR.H,如下所示:
typedef unsigned short wchar_t;因此,wchar_t数据类 型和一个无符号短整形一样是16位宽。
wchar_t c = 'A';变量c是一个两字节的值0x0041,这是Unicode中字母A的值。
wchar_t *p = L"hello!";这里注意,字符串前面的‘L’表示长整形,这是为了表面字符串是宽字符串,也就是说字符串中的每个字符都以宽字符存储,即每个字符占2个字节。 指针变量还是4个字节的存储空间,但是字符串的存储空姐则需要14个字节(7个字符,其中一个'\0')。
satatic wchar_t a[] = L"hello!";
这个字符串同样需要14个字节的存储空间。单个宽字符常量的前面加‘L’,但是通常不需要。C编译器总是会在单个字符后面加一个'\0'的。
2.2.3 宽字符库函数
你在C语言中使用的以字符串参数的运行库函数都有宽字符的版本。这些函数都被定义在WCHAR.H和定义正常函数的头文件中。
2.2.4 维护一个源代码文件
使用Unicode肯定也用一些缺点,比如说字符占有空间大,是char型的2倍。怎样来解决这个问题呢?一个解决方案就是使用包含在Microsoft Visual C++中的TCHAR.H头文件。TCHAR.H为那些需要字符串参数的普通运行库函数提供可一些列的替代名称。这些函数有时被称为“通用”的函数名字,因为这样可以区别出Unicode版或非Unicode版本的函数。
如果一个_Unicode的标示符被定义了并且TCHAR.H包含在你的程序中,_tsclen被定义为wcslen:
#definef _tsclen wcslen如果Unicode没有被定义,则_tsclen被定义为strlen:
#definef _tsclen strlen同理,其他函数也被这样定义,如:
#definef __T(x) L##x #definef __T(x) x #definef _T(x) __T(x) #definef _TEXT(x) __T(x)
2.3 宽字符和windows
windows NT从底册支持Unicode。
2.3.1 window头文件的类型
WINNT.H负责处理基本的Unicode值成功能。
WINNT.H在一开始就包含C的头文件CTYPE.H,而这是C的众多头文件之一,包含着wchar_t的定义。 WINNT.H定义了两个新的被称作CHAR和WCHAR的数据类型:
typedef char CHAR; typedef wchar_t WCHAR; //wcCHAR和WCHAR是写windows程序时推荐使用的数据类型,它们分别定义8位和16位的字符。
WINNT.H头文件还定义了可用做8位字符串指针的6种数据类型和可用做const 8位字符串指针的4种数据类型。可在WINNT.H中查看。
2.3.2 windows函数调用
windows支持Unicode的关键是:在USER32.DLL中,并没有32位MessageBox函数的入口点。实际上,它有有两个入口点,一个名为MessageBoxA(ASCII版),另一个名为MessageBoxW(宽字符版)。像这样的用字符串作参数的每个Win32函数,都在操作系统中有两个入口点!幸运的是,我们不必当心这个问题,我们只需在写程序是使用MessageBox函数即可。就像TCHAR一样,在windows头文件中都使用了一些技巧。
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 #else #define MessageBox MessageBoxA #endif // !UNICODE2.3.3 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标示符时,这些函数就接受宽字符串, 否则只接受常规字符串。
2.3.4 在windows中使用printf
在windows程序中不能使用printf函数,但是仍然可以使用sprintf和sprintf系列的其他函数来显示文本。
2.3.5 格式化的消息框
*----------------------------------------------------- SCRNSIZE.C -- Displays screen size in a message box (c) Charles Petzold, 1998 -----------------------------------------------------*/ #include <windows.h> #include <tchar.h> #include <stdio.h> 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函数得到。
第二章完