关于 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
#defineCreateWindowEx CreateWindowExW
#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