>原著:Michael Dunn& G0 {' S6 |6 @* j: N7 l" p$ V, ]
>原文出处:<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>4 F& }! Y* c' _. k1 C
>
><B>引言</B>: {: U+ ?: q+ v9 u2 z
RE>wchar_t wch = L''1''; // 2 bytes, 0x00310 D1 j/ q; [0 I; E* S
><IMG src="http://www.vckbase.com/document/image/paragraph.gif"> <B>字符在内存中是怎样存储的</B>; G1 I" R M! C) O S
>Unicode的存储形式,L"Bob"</P>
>使用两个字节表示的0来做结束标志。% Q; B5 ~* s8 N7 \/ B
>值得注意的是,"ni"的值不能被解释成WORD型值0xfa93,而应该看作两个值93和fa以这种顺序被作为"ni"的编码。4 o$ Z+ f9 j& ?
> 因为x86CPU是little-endian,值0x0042在内存中的存储形式是42 00。你能看出如果这个字符串被传给strlen()函数会出现什么问题吗?它将先看到第一个字节42,然后是00,而00是字符串结束的标志,于是strlen()将会返回1。如果把"Bob"传给wcslen(),将会得出更坏的结果。wcslen()将会先看到0x6f42,然后是0x0062,然后一直读到你的缓冲区的末尾,直到发现00 00结束标志或者引起了GPF。; t4 {3 h9 J. g, e
> 我们先来阐述规则2,因为找到一个违背它的真实的实例代码是很容易的。假设你有一个程序在你自己的目录里保存了一个设置文件,你把安装目录保存在注册表中。在运行时,你从注册表中读取安装目录,然后合成配置文件名,接着读取该文件。假设,你的安装目录是C:\Program Files\MyCoolApp,那么你合成的文件名应该是C:\Program Files\MyCoolApp\config.bin。当你进行测试时,你发现程序运行正常。- M0 W+ T; b2 r3 x# Z
RE>bool GetConfigFileName ( char* pszName, size_t nBuffSize )- \5 T) L: T' `; f& L
> 当使用 GetConfigFileName() 检查尾部的''\\''时,它寻找安装目录名中最后的非0字节,看它是等于''\\''的,所以没有重新增加一个''\\''。结果是代码返回了错误的文件名。2 T& m" @0 q% W: f p" s1 }
RE>bool FixedGetConfigFileName ( char* pszName, size_t nBuffSize )( G+ }! \8 |* |- ^6 x0 c' q& {9 A
RE>2a. 永远不要使用减法去得到一个字符串的索引。</PRE>- r. j' p- w( d5 q
>违背这条规则的代码和违背规则2的代码很相似。例如,</P><
RE>char* pLastChar = &szConfigFilename [strlen(szConfigFilename) - 1];</PRE>7 [$ K& g' b, O y; H4 N
>这和向后移动一个指针是同样的效果。+ n/ b e. t2 C% s9 A1 p4 E! T
RE>BOOL WINAPI SetWindowTextA ( HWND hWnd, LPCSTR lpString );
RE>#define SetWindowText SetWindowTextA</PRE>9 j! c& Y K6 \2 j3 _7 t4 r* P/ [
> 这个宏定义把所有对SetWindowText的调用都转换成真正的API函数SetWindowTextA。(当然,你可以直接调用SetWindowTextA() 或者 SetWindowTextW(),虽然你不必那么做。)6 b5 ^8 W$ Q! D' C: U3 U
RE>HWND hwnd = GetSomeWindowHandle();1 m; B4 ]0 a7 y6 y" |/ ?
>在预处理器把SetWindowText用SetWindowTextW来替换后,代码变成:</P><
RE>HWND hwnd = GetSomeWindowHandle();
> 看到问题了吗?我们把单字节字符串传给了一个以Unicode字符串做参数的函数。解决这个问题的第一个方案是使用 #ifdef 来包含字符串变量的定义:</P><
RE>HWND hwnd = GetSomeWindowHandle();8 |: ~# w* y+ |0 \. W( W4 w4 @3 y
>你可能已经感受到了这样做将会使你多么的头疼。完美的解决方案是使用TCHAR.! t) M& j- c7 g
RE>#ifdef UNICODE4 Z3 b$ P0 `# b: L. n% f+ F
>所以用MBCS来build时,TCHAR是char,使用UNICODE时,TCHAR是wchar_t。还有一个宏来处理定义Unicode字符串常量时所需的L前缀。</P><
RE>#ifdef UNICODE( j; C) `# ~3 z Q4 \8 o# X| 欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) | Powered by Discuz! X2.5 |