>原著:Michael Dunn) C- ]5 l% N1 V. x+ t. F0 {( W+ @
>原文出处:<FONT size=2><a href="http://www.codeproject.com/string/cppstringguide1.asp" target="_blank" >CodeProject:The Complete Guide to C++ Strings, Part I</A></FONT></P>2 J! W( _% ~$ I& K# p; {" A
>3 z6 k7 s { z& V, r l2 F& ?
><B>引言</B>/ C) O! S, k6 m% @. b/ T% z% B( Y
RE>wchar_t wch = L''1''; // 2 bytes, 0x0031# w' |8 _$ g% W1 t f5 l4 V
><IMG src="http://www.vckbase.com/document/image/paragraph.gif"> <B>字符在内存中是怎样存储的</B>/ e2 [( L* j( s; ?9 d4 C5 V. p+ e
>Unicode的存储形式,L"Bob"</P># V( {. F$ s# m, `7 k
>使用两个字节表示的0来做结束标志。# b! x0 L, p- U
>值得注意的是,"ni"的值不能被解释成WORD型值0xfa93,而应该看作两个值93和fa以这种顺序被作为"ni"的编码。
> 因为x86CPU是little-endian,值0x0042在内存中的存储形式是42 00。你能看出如果这个字符串被传给strlen()函数会出现什么问题吗?它将先看到第一个字节42,然后是00,而00是字符串结束的标志,于是strlen()将会返回1。如果把"Bob"传给wcslen(),将会得出更坏的结果。wcslen()将会先看到0x6f42,然后是0x0062,然后一直读到你的缓冲区的末尾,直到发现00 00结束标志或者引起了GPF。
> 我们先来阐述规则2,因为找到一个违背它的真实的实例代码是很容易的。假设你有一个程序在你自己的目录里保存了一个设置文件,你把安装目录保存在注册表中。在运行时,你从注册表中读取安装目录,然后合成配置文件名,接着读取该文件。假设,你的安装目录是C:\Program Files\MyCoolApp,那么你合成的文件名应该是C:\Program Files\MyCoolApp\config.bin。当你进行测试时,你发现程序运行正常。
RE>bool GetConfigFileName ( char* pszName, size_t nBuffSize )6 N, @" p8 R( ~* h1 z$ |1 E5 T6 l
> 当使用 GetConfigFileName() 检查尾部的''\\''时,它寻找安装目录名中最后的非0字节,看它是等于''\\''的,所以没有重新增加一个''\\''。结果是代码返回了错误的文件名。
RE>bool FixedGetConfigFileName ( char* pszName, size_t nBuffSize )5 D- z p$ q2 z! ~4 @8 H7 y
RE>2a. 永远不要使用减法去得到一个字符串的索引。</PRE>( b3 M. u5 c T1 G* G! w
>违背这条规则的代码和违背规则2的代码很相似。例如,</P><
RE>char* pLastChar = &szConfigFilename [strlen(szConfigFilename) - 1];</PRE>1 ] v+ e( n- N4 Z) ^+ X, @- E
>这和向后移动一个指针是同样的效果。0 U' {, M1 a; i, z
RE>BOOL WINAPI SetWindowTextA ( HWND hWnd, LPCSTR lpString );
RE>#define SetWindowText SetWindowTextA</PRE>3 l, X* X0 q0 O7 f* T
> 这个宏定义把所有对SetWindowText的调用都转换成真正的API函数SetWindowTextA。(当然,你可以直接调用SetWindowTextA() 或者 SetWindowTextW(),虽然你不必那么做。)
RE>HWND hwnd = GetSomeWindowHandle();
>在预处理器把SetWindowText用SetWindowTextW来替换后,代码变成:</P><
RE>HWND hwnd = GetSomeWindowHandle();/ I% l, ~9 K; }( O2 u
> 看到问题了吗?我们把单字节字符串传给了一个以Unicode字符串做参数的函数。解决这个问题的第一个方案是使用 #ifdef 来包含字符串变量的定义:</P><
RE>HWND hwnd = GetSomeWindowHandle();; O# R5 n ^: W @% ^& d7 ?, {9 @
>你可能已经感受到了这样做将会使你多么的头疼。完美的解决方案是使用TCHAR.
RE>#ifdef UNICODE. E7 D5 r. F/ Y' [
>所以用MBCS来build时,TCHAR是char,使用UNICODE时,TCHAR是wchar_t。还有一个宏来处理定义Unicode字符串常量时所需的L前缀。</P><
RE>#ifdef UNICODE| 欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) | Powered by Discuz! X2.5 |