• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            飄雪

            C++博客 首頁 新隨筆 聯系 聚合 管理
              31 Posts :: 0 Stories :: 60 Comments :: 0 Trackbacks
                vc 2005 sp1下isspace函數的debug版本對中文處理有問題

                今天碰到一個怪問題,從別人那兒拿來的一段代碼先在gcc下過了,又移植到vc下編譯,結果debug時老是有assert錯誤。看了一下代碼,錯誤發生在一個trim函數中。trim函數接受一個char*類型的字符串參數,去掉字符串前后的空格、制表符等空白字符。其中判斷是否是空白字符用的是isspace函數。按照一般的想法,char*字符串里的字符編碼無論是GBK還是utf-8,因為都兼容ASCII,所以isspace函數都不應該發生問題。但事實是只要是字符串有中文,無論是gbk還是utf-8編碼,isspace內都有assert錯誤。為了便于說明,把其中的代碼抽像出來如下:

                char* lpszBuffer = (char*)"高";
                int nLen = (int)strlen(lpszBuffer);
                for( int i=0;i
                {
                    printf("0x%x %dn",lpszBuffer[i],isspace(lpszBuffer[i]) );
                }

                這段代碼在debug編譯的情況下會assert失敗。沒有辦法,只好跟蹤到c運行庫里,isspace的實現如下(在"_ctype.c"文件里):

            extern __inline int (__cdecl isspace) (
                    int c
                    )
            {
                if (__locale_changed == 0)
                {
                    return __fast_ch_check(c, _SPACE);
                }
                else
                {
                    return (_isspace_l)(c, NULL);
                }
            }

                跟蹤發現,__locale_changed的值為0,走第一個分支,調用__fast_ch_check,它其實是個宏定義,最后進入_chvalidator函數,它的實現代碼如下:

            extern "C" int __cdecl _chvalidator(
                    int c,
                    int mask
                    )
            {
                    _ASSERTE((unsigned)(c + 1) <= 256);
                    return _chvalidator_l(NULL, c, mask);
            }

                錯誤就發生在這個函數的第一行“ _ASSERTE((unsigned)(c + 1) <= 256);”。
                
                代碼看到這里,錯誤的原因基本也就出來了。“高”的GBK編碼是“b8 df”,調用isspace函數是逐個字節判斷,但是isspace和_chvalidator接受的參數都是int,這樣就會產生一個char到int的轉型,在vc下,char默認是"signed char",這樣char“b8”轉型到int后,會變成一個負數,然后在assert的時候,又強制轉型為unsigned,它又變成了一個非常巨大的正數,自然assert就失敗了。
                為什么在gcc下沒有錯誤?gcc下的isspace函數實現我倒沒看,不過我的gcc中的char默認就是“unsighed char”,所以即使isspace的實現跟上面的一樣,也不會產生問題。
                另:在win32 release和wince下,也不會有上述問題,因為這幾種環境下isspace的實現跟上面不一樣。
                
                問題找到了,剩下的就看怎么解決了。
                首先用用一個最簡單的方法,既然問題發生在轉型上,只要把char的默認類型改為unsigned char就可以了,vc也提供了這個選項。但這有幾個問題,一是別人用我的代碼的時候還得修改編譯選項,二是修改了整個工程的編譯選項可能會對其它代碼產生不好的影響。
                既然上面的方法不大好操作,那就再想想別的方法。經觀察發現,isspace函數中靠__locale_changed變量控制流程走向,搜索整個crt的源代碼,發現__locale_changed的值只有在setlocale函數中發生了改變。最后,我把代碼修改成如下:

                #if defined(WIN32) && defined(_DEBUG)
                char* locale = setlocale( LC_ALL, ".OCP" );
                #endif
                char* lpszBuffer = (char*)"高";
                int nLen = (int)strlen(lpszBuffer);
                for( int i=0;i
                {
                    printf("0x%x %dn",lpszBuffer[i],isspace(lpszBuffer[i]) );
                }
               
                這樣在debug版本上就不會再有問題,但是可能其中仍有隱患,等到具體碰到的時候再說吧。先把目前的工作繼續下去。

            posted on 2009-03-12 14:04 飄雪 閱讀(4691) 評論(5)  編輯 收藏 引用
            青草影院天堂男人久久| 欧美久久综合九色综合| 伊人热热久久原色播放www| 国产福利电影一区二区三区久久老子无码午夜伦不 | 深夜久久AAAAA级毛片免费看 | 精品久久久久久国产| 亚洲国产成人乱码精品女人久久久不卡| 久久精品一区二区国产| 久久久无码精品亚洲日韩蜜臀浪潮 | 久久久久青草线蕉综合超碰| 三级三级久久三级久久| 欧美日韩精品久久久久| 日韩人妻无码一区二区三区久久99| 伊人久久大香线蕉综合5g| 亚洲另类欧美综合久久图片区| 无码任你躁久久久久久老妇App| 亚州日韩精品专区久久久| 久久久国产打桩机| 久久久久亚洲AV无码专区体验| 久久99精品久久久久子伦| 国产成人综合久久精品尤物| 亚洲国产日韩欧美综合久久| 18岁日韩内射颜射午夜久久成人| 亚洲精品乱码久久久久66| 大伊人青草狠狠久久| 久久影视综合亚洲| 亚洲va中文字幕无码久久| 久久免费美女视频| 色婷婷久久综合中文久久一本| 久久久久国产精品人妻| 久久天堂电影网| 久久笫一福利免费导航| 国产精品久久毛片完整版| 久久久久久亚洲精品无码| 亚洲中文字幕无码久久精品1| 久久精品国产半推半就| 久久久久一级精品亚洲国产成人综合AV区| 久久青青色综合| 青青青国产精品国产精品久久久久| 久久青青草视频| 精品久久久久久无码免费|