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