您的位置:首页 > 编程语言

关于Windows系统下编程之字符处理

2007-11-02 22:07 465 查看
关于Windows系统下编程之字符处理

我们在widows下编程时,经常遇到关于字符串的处理的问题,特别是在用VC编程时,我们经常犯错误,所以我结合我的编程经验和我学习widows核心编程这本书后的体会,来自己作一个总结。
1、字符集
在我们平时的编代码的过程中,总在不但地处理各种关于字符集的问题。对于我们来说,习惯于将文本串作为一系列单字节字符串来处理,并且在结尾加上”/0”,它用来标识串的结束。当我们调用strlen(…)函数时,它在以0 结尾的单字节字符数组中返回字符的数目。
2、单字节与双字节字符集
一个字节占用8位(bit)。而双字节字符集中,字符串中的每个字符在编码时可以包含一个字节或包含两个字节(这时strlen(…)函数就不能告诉我们字符串中究竟有多少个字符,它只能告诉我们在该字符串中的第一个”/0”之前有多少个字节。在VC中,我们可以用_mbslen(…)来代替。)。
3、Unicode字符集
Unicode字符集提供了简单而有一致的表示字符串的方法,它规定字符串中每一个字符编码都是16位(两个字节)。所以利用Unicode字符集可以编码216 = 65535个字符。这样,它就能够对世界各国的书面文字中的所有字符进行编码,远远超过了单字节字符集的2 5 6 个字符的数目。

部分Unicode区域字符表

1 6 位代码
字符
16 位代码
字符
0 0 0 0 - 0 0 7 F
A S C I I
0 3 0 0 - 0 3 6 F
通用区分标志
0 0 8 0 - 0 0 F F

拉丁文1 字符
0 4 0 0 - 0 4 F F

西里尔字母
0 1 0 0 - 0 1 7 F
欧洲拉丁文
0 5 3 0 - 0 5 8 F
亚美尼亚文
0 1 8 0 - 0 1 F F

扩充拉丁文
0 5 9 0 - 0 5 F F

西伯莱文
0 2 5 0 - 0 2 A F

标准拼音
0 6 0 0 - 0 6 F F

阿拉伯文
0 2 B 0 - 0 2 F F

修改型字母
0 9 0 0 - 0 9 7 F
梵文
4、windows与Unicode
我们基本上天天和Windows打交道,知道Windows 2000/XP是用Unicode进行开发的。在Windows 2000/XP中用于创建窗口、呈现文本、进行字符串操作等所有核心函数都需要Unicode字符串。在平时我们调用任何一个Windows函数并给它传递一个ANSI字符串,那么系统首先要将字符串转换成Unicode,然后将Unicode字符串传递给操作系统。如果希望函数返回ANSI字符串,系统就会首先将Unicode字符串转换成ANSI字符串,然后将结果返回给你的应用程序。所有这些转换操作都是在你看不见的情况下发生的。当然,进行这些字符串的转换需要占用系统的时间和内存。
例如,如果调用CreateWindowEx函数,并传递类名字和窗口标题文本的非Unicode字符串,那么CreateWindowEx必须分配内存块(在你的进程的默认堆中),将非Unicode字符串转换成Unicode字符串,并将结果存储在分配到的内存块中,然后调用Unicode版本的CreateWindowEx函数。对于用字符串填入缓存的函数来说,系统必须首先将Unicode字符串转换成非Unicode字符串,然后你的应用程序才能处理该字符串。由于系统必须执行所有这些转换操作,因此你的应用程序需要更多的内存,并且运行的速度比较慢。通过从头开始用Unicode来开发应用程序,就能够使你的应用程序更加有效地运行。
5、编写Unicode源代码
①C运行期库对Unicode的支持
为了利用Unicode字符串,定义了一些数据类型,如我们熟悉的wchar_t
typedef unsigned short wchar_t;

eg:wchar_t szBuffer[100] ;//在内存中的大小为100*18bit = 200 byte。可以存储最多为9 9 个字符的Unicode字符串和一个结尾为零的字符

现在一些标准的ANSI的C字符串处理函数都有相应的等价的Unicode函数。如:
eg:char * strcat(char *,const char *);

char_t * wcscat(wchar_t *,const wchar_t *)

标准的ANSI C 字符串函数和它们的等价Unicode函数
char * strchr(const char *,int);

wchar_t * wcschr(const wchar_t *,wchar_t);


int strcmp(const char *,const char *);

int wcscmp(const wchar_t *,const wchar_t *);


char * strcpy(char *,const char *);

wchar_t * wcscpy(wchar_t *,const wchar_t *);


size_t strlen(const char *);

size_t wcslen(const wchar_t *);

注意:所有的Unicode函数均是以wcs开头,而ANSI函数则以str开头

②Tchar,h头文件
Tchar.h 文件的唯一作用是帮助创建ANSI/Unicode通用源代码文件。它包含你应该用在源代码中的一组宏,而不应该直接调用str函数或者wcs函数。如果在编译源代码文件时定义了UNICODE,这些宏就会引用wcs这组函数。如果没有定义_UNICODE,那么这些宏将引用str这组宏。
A WCHAR if UNICODE is defined, a CHAR otherwise

#ifdef UNICODE
typedef WCHAR TCHAR;
#else typedef char TCHAR;
#endif

所以根据上面的定义我们可以将TCHAR看为通用的字符类型。
eg: TCHAR szBuffer[100];
TCHAR ch = “Hello”;
注意:TCHAR ch = “Hello”这行代码在Visual C++中,如果没有定义_UNICODE,编译是按ANSI编码,可以通过(在VC中默认是ANSI编码)。但当我们定义了_UNICODE时,编译就通不过,我们必须改成TCHAR ch = L“Hello”。字符串(literal string )前面的大写字母L ,用于告诉编译器该字符串应该作为Unicode字符串来编译。当编译器将字符串置于程序的数据部分中时,它在每个字符之间分散插入零字节。这种变更带来的问题是,现在只有当定义了_UNICODE时,程序才能成功地进行编译。我们需要另一个宏,以便有选择地在字符串的前面加上大写字母L 。这项工作由_TEXT宏来完成,_TEXT宏也在T C h a r. h 文件中做了定义。

如果定义了_UNICODE,那么_TEXT定义为下面的形式:
#define_TEXT(x) __T(x)
#define__T(x) L## x
如果没有定义_UNICODE,那么_TEXT定义为下面的形式:
#define _TEXT(x) x

所以使用该宏,可以改写上面这行代码为TCHAR ch = _TEXT(“Hello”),这样,无论是否定义了_UNICODE宏,它都能够正确地进行编译。

③Windows定义的Unicode数据(This type is declared in WinNT.h)

Typedef wchar_t WCHAR; //16-bit Unicode Characters

Typedef WCHAR *PWSTR;//Pointer to a new null-terminated //string of 16-bitUnicode characters

Typedef CONST WCHAR *PCWSTR;//Pointer to a constant //null-terminated string of //16-bit Unicode characters

A PWSTR if UNICODE is defined, a PSTR otherwise

#ifdef UNICODE

typedef LPWSTR PTSTR;
#else

typedef LPSTR PTSTR;

#endif

A PCWSTR if UNICODE is defined, a PCSTR otherwise.

#ifdef UNICODE
typedef LPCWSTR PCTSTR;
#else
typedef LPCSTR PCTSTR;
#endif

windows中的Unicode函数和ANSI函数
前面我说过,在Windows中有好多的函数有两个版本,一个接受Unicode字符串,一个接受ANSI串,如:
#ifdefUNICODE
#defineCreateWindowExCreateWindowExW
#else
#define CreateWindowEx CreateWindowExA
#endif// !UNICODE
当编译源代码模块时,UNICOD是否已经作了定义,将决定你调用的是哪个CreateWindowEx版本。当转用一个1 6 位的Windows应用程序时,你在编译期间可能没有定义UNICODE。对CreateWindowEx函数的任何调用都会将该宏扩展为对CreateWindowExA的调用,即对CreateWindowEx的A N S I 版本的调用。由于1 6 位Wi n d o w s 只提供了C r e a t e Wi n d o w s E x 的A N S I 版本,因此可以比较容易地转用它的应用程序。如果定义了UNICODE,则是对CreateWindowExW调用。
UnicodeANSI之间转换字符串
MultiByteToWideChar(…)用于将多字节字符串转换成宽字节字符串

int MultiByteToWideChar(
UINT CodePage, //标识一个与多字节字符串相关的代码页号
DWORD dwFlags, //Flags indicating the conversion type
LPCSTR lpMultiByteStr, //要转换的字符串指针
int cbMultiByte, //用与指明源串的长度(以字节计算),如果传值为-1//那么函数返回源串的长度;0,则失败
LPWSTR lpWideCharStr,//目标串的地址
int cchWideChar //目标串的长度(以自己计算),如果传值为0,则函数不//执行转换,而是返回使转换成功所需要的缓存的值.
);

WideCharToMultiByte)用于将宽字节字符串转换成等价的多字节字符串
int WideCharToMultiByte(
UINT CodePage,
DWORD dwFlags,
LPCWSTR lpWideCharStr,
int cchWideChar,
lpMultiByteStr,
int cbMultiByte,
LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar );
由于和MultiByteToWideChar(…)差不多,所以可以对比着看MSDN

有错误欢迎大家指正,请发邮件到Leezhm@126.com



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: