关于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区域字符表
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函数。如:
标准的ANSI C 字符串函数和它们的等价Unicode函数
注意:所有的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调用。
⑤在Unicode与ANSI之间转换字符串
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
![](http://simg.vdoing.com/m/54977/x01.gif?noscript)
我们在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 | 梵文 |
我们基本上天天和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调用。
⑤在Unicode与ANSI之间转换字符串
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
![](http://simg.vdoing.com/m/54977/x01.gif?noscript)
相关文章推荐
- 关于Windows系统下编程之字符处理
- Windows 系统编程初探 (四)结构化异常处理之一:SEH的基本原理与进程相关异常处理
- windows核心编程心解--字符和字符串处理
- 【Windows 核心编程】Windows 核心编程 -- 字符和字符串处理
- Windows编程-1-字符和字符串处理相关知识点总结
- windows编程中字符和字符串的处理
- Windows核心编程--错误处理/字符/字符串
- Windows 系统编程初探 (五)结构化异常处理之二:线程相关异常处理
- 关于Linux系统编程的错误处理:errno、perror、strerror
- 关于C++中文字符的处理
- 关于windows的进程处理(五)
- Java 编程中关于异常处理的 10 个最佳实践
- 开始进行 64 位 Windows 系统编程之前需要了解的所有信息
- windows系统调用int 2e处理过程
- 编程实现不重启Windows系统直接更改IP配置
- 关于处理GET方式提交的含有特殊字符的参数
- VC Windows shell扩展编程(为系统右键菜单添加二级菜单傻瓜教程)
- 关于iOS中webView中url特殊字符处理
- Delphi编程--字符处理
- 关于windows的safari浏览器的parseInt()函数处理08和09异常问题