CString 的 Bug(MFC42)

前兩天在處理一個字符串的時候發現一個奇怪的現象:當刪除字符串中的引號時,後面的中文都變成了亂碼,搞得我一頭霧水。

一看內存,發現中文字符的前後兩個字節被分了家:一個字節巋然不動,一個字節根據刪除減少的字符數向前移動。

這就奇怪了,難道是MFC的問題??

跟進去一看,果不其然! MFC42 (vs6)是這麼處理的:


CString::Remove(TCHAR ch)

......

 while (pstrSource < pstrEnd)
 {
  if (*pstrSource != chRemove)
  {
   *pstrDest = *pstrSource;
   pstrDest = _tcsinc(pstrDest);
  }
  pstrSource = _tcsinc(pstrSource);
 }

MFC42其實考慮到了MBCS的情況, 所以用了 _tcsinc來判斷下一字符的位置;可惜只考慮了一半,賦值時

*pstrDest = *pstrSource

可不像它想象的那麼聰明,只能根據類型定義拷貝了單個字節。 所以就發生了刪除一個字符後,後面的字符往前移動時只移動了雙字節字符的前一個字節的情況。

根據源代碼的意思,實際上刪除任何一個字符,其後面的中文字符串都會亂掉。

字符串的處理是個蠻古董的話題了,出現這樣子的bug確實讓我吃了一驚。剛好手頭還有vs2003, 於是試了試,發現已經更改過來了。

代碼如下:

  while( pszSource < pszEnd )
  {
   PXSTR pszNewSource = StringTraits::CharNext( pszSource );
   if( *pszSource != chRemove )
   {
    // Copy the source to the destination.  Remember to copy all bytes of an MBCS character
    PXSTR pszNewDest = pszDest+(pszNewSource-pszSource);
    while( pszDest != pszNewDest )
    {
     *pszDest = *pszSource;
     pszSource++;
     pszDest++;
    }
   }
   pszSource = pszNewSource;
  }

可以看到MFC(7.1)特地用了一個while循環來處理多字節字符的情況。這次,MFC(7.1)記起來了,還在代碼里加了註釋。它說:

“Remember to copy all bytes of an MBCS character”

我想看看msdn上對於這個bug的說法, 於是google了一把 “CString Remove Bug Site:microsoft.com”。

這一Google沒發現Remove的說明, 卻又發現了Right, Left, Mid的bug說明:

KB810448:FIX: CString Functions Right, Left, and Mid May Cause Access Violation.

文章最後說明,該bug存在於MFC42(visul studio 6), Visual C++ .NET 2002 Standard Edition中。

有了前次的經歷,Right, Left, Mid在MFC42中有問題就不那麼嚇人樂,不過在vs2002中還存在,就有點......

由於沒找到關於 CString::Remove 的 bug說明,因此寫了這篇文章,提醒還在使用 vs2003之前版本的朋友們,慎用 CString 的 Remove, Right, Left, Mid。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章