分类: LINUX
2007-11-11 09:26:15
上面的函数使用CharPrev() API使pLastChar向后移动一个字符,这个字符可能是两个字节长。在这个版本里,if条件正常工作,因为lead byte永远不会等于0x
让我们来想象一个违背规则1的场合。例如,你可能要检测一个用户输入的文件名是否多次出现了:。如果,你使用++操作来遍历字符串,而不是使用CharNext(),你可能会发出不正确的错误警告如果恰巧有一个trail byte它的值的等于:的值。
与规则2相关的关于字符串索引的规则:
违背这条规则的代码和违背规则2的代码很相似。例如,
char* pLastChar = &szConfigFilename [strlen(szConfigFilename) - 1];
这和向后移动一个指针是同样的效果。
回到关于str***()和_mbs***()的区别
现在,我们应该很清楚为什么_mbs***()函数是必需的。Str***()函数根本不考虑DBCS字符,而_mbs***()考虑。如果,你调用strrchr(C:\\ , \\),返回结果可能是错误的,然而_mbsrchr()将会认出最后的双字节字符,返回一个指向真的\\的指针。
关于字符串函数的最后一点:str***()和_mbs***()函数认为字符串的长度都是以char来计算的。所以,如果一个字符串包含3个双字节字符,_mbslen()将会返回6。Unicode函数返回的长度是按wchar_t来计算的。例如,wcslen(LBob)返回3。
Win32 API中的MBCS和Unicode
两组 APIs:
尽管你也许从来没有注意过,Win32中的每个与字符串相关的API和message都有两个版本。一个版本接受MBCS字符串,另一个接受Unicode字符串。例如,根本没有SetWindowText()这个API,相反,有SetWindowTextA()和SetWindowTextW()。后缀A表明这是MBCS函数,后缀W表示这是Unicode版本的函数。
当你 build 一个 Windows ,你可以选择是用 MBCS 或者 Unicode APIs。如果,你曾经用过VC向导并且没有改过预处理的设置,那表明你用的是MBCS版本。那么,既然没有 SetWindowText() API,我们为什么可以使用它呢?winuser.h头文件包含了一些宏,例如:
当使用MBCS APIs来build时,UNICODE没有被定义,所以预处理器看到:
#define SetWindowText SetWindowTextA
这个宏定义把所有对SetWindowText的调用都转换成真正的API函数SetWindowTextA。(当然,你可以直接调用SetWindowTextA() 或者 SetWindowTextW(),虽然你不必那么做。)
所以,如果你想把默认使用的API函数变成Unicode版的,你可以在预处理器设置中,把_MBCS从预定义的宏列表中删除,然后添加UNICODE和_UNICODE。(你需要两个都定义,因为不同的头文件可能使用不同的宏。) 然而,如果你用char来定义你的字符串,你将会陷入一个尴尬的境地。考虑下面的代码:
在预处理器把SetWindowText用SetWindowTextW来替换后,代码变成:
看到问题了吗?我们把单字节字符串传给了一个以Unicode字符串做参数的函数。解决这个问题的第一个方案是使用 #ifdef 来包含字符串变量的定义:
使用TCHAR
TCHAR是一种字符串类型,它让你在以MBCS和UNNICODE来build时可以使用同样的代码,不需要使用繁琐的宏定义来包含你的代码。TCHAR的定义如下:
#ifdef UNICODEtypedef wchar_t TCHAR;#elsetypedef char TCHAR;#endif
所以用MBCS来build时,TCHAR是char,使用UNICODE时,TCHAR是wchar_t。还有一个宏来处理定义Unicode字符串常量时所需的L前缀。
#ifdef UNICODE#define _T(x) L##x#else#define _T(x) x#endif
##是一个预处理操作符,它可以把两个参数连在一起。如果你的代码中需要字符串常量,在它前面加上_T宏。如果你使用Unicode来build,它会在字符串常量前加上L前缀。
TCHAR szNewText[] = _T(we love Bob!);
像是用宏来隐藏SetWindowTextA/W的细节一样,还有很多可以供你使用的宏来实现str***()和_mbs***()等字符串函数。例如,你可以使用_tcsrchr宏来替换strrchr()、_mbsrchr()和wcsrchr()。_tcsrchr根据你预定义的宏是_MBCS还是UNICODE来扩展成正确的函数,就像SetWindowText所作的一样。
不仅str***()函数有TCHAR宏。其他的函数如, _stprintf(代替sprinft()和swprintf()),_tfopen(代替fopen()和_wfopen())。 MSDN中Generic-Text Routine Mappings.标题下有完整的宏列表。
字符串和TCHAR typedefs
由于Win32 API文档的函数列表使用函数的常用名字(例如,SetWindowText),所有的字符串都是用TCHAR来定义的。(除了XP中引入的只适用于Unicode的API)。下面列出一些常用的typedefs,你可以在msdn中看到他们。
type |
Meaning in MBCS builds |
Meaning in Unicode builds |
WCHAR |
wchar_t |
wchar_t |
LPSTR |
zero-terminated string of char (char*) |
zero-terminated string of char (char*) |
LPCSTR |
constant zero-terminated string of char (const char*) |
constant zero-terminated string of char (const char*) |
LPWSTR |
zero-terminated Unicode string (wchar_t*) |
zero-terminated Unicode string (wchar_t*) |
LPCWSTR |
constant zero-terminated Unicode string (const wchar_t*) |
constant zero-terminated Unicode string (const wchar_t*) |
TCHAR |
char |
wchar_t |
LPTSTR |
zero-terminated string of TCHAR (TCHAR*) |
zero-terminated string of TCHAR (TCHAR*) |
LPCTSTR |
constant zero-terminated string of TCHAR (const TCHAR*) |
constant zero-terminated string of TCHAR (const TCHAR*) |
何时使用 TCHAR 和 Unicode
到现在,你可能会问,我们为什么要使用Unicode。我已经用了很多年的char。下列3种情况下,使用Unicode将会使你受益:
· 1.你的只运行在Windows NT中。
· 2. 你的需要处理超过MAX_PATH个字符长的文件名。
· 3. 你的需要使用XP中引入的只有Unicode版本的API.
Windows 9x 中大多数的 API 没有实现 Unicode 版本。所以,如果你的要在windows 9x中运行,你必须使用MBCS APIs。然而,由于NT内部都使用Unicode,所以使用Unicode APIs将会加快你的的运行速度。每次,你传递一个字符串调用MBCS API,操作会把这个字符串转换成Unicode字符串,然后调用对应的Unicode API。如果一个字符串被返回,操作还要把它转变回去。尽管这个转换过程被高度优化了,但它对速度造成的损失是无法避免的。
只要你使用Unicode API,NT允许使用非常长的文件名(突破了MAX_PATH的限制,MAX_PATH=260)。使用Unicode API的另一个优点是你的会自动处理用户输入的各种语言。所以一个用户可以输入英文,中文或者日文,而你不需要额外编写代码去处理它们。
最后,随着windows 9x产品的淡出,微软似乎正在抛弃MBCS APIs。例如,包含两个字符串参数的SetWindowTheme() API只有Unicode版本的。使用Unicode来build你的将会简化字符串的处理,你不必在MBCS和Unicdoe之间相互转换。
即使你现在不使用Unicode来build你的,你也应该使用TCHAR及其相关的宏。这样做不仅可以的代码可以很好地处理DBCS,而且如果将来你想用Unicode来build你的,你只需要改变一下预处理器中的设置就可以实现。
对各字符集编码范围的总结
[精华] [分享]对各字符集编码范围的总结[更新日期2007-03-12] | |
---|---|
作者: 发表于:2007-04-09 11:26:30 | |
【】 【】 【】【】 | |
|