??xml version="1.0" encoding="utf-8" standalone="yes"?>欧美一区二区三区视频在线,欧美日韩高清在线一区,狠狠色综合日日http://www.shnenglu.com/sigepluto/category/7799.htmlC++夜未?/description>zh-cnSun, 28 Mar 2010 06:03:26 GMTSun, 28 Mar 2010 06:03:26 GMT60MFC中一个危险的Bughttp://www.shnenglu.com/sigepluto/archive/2010/03/26/110622.htmlJakcieJakcieFri, 26 Mar 2010 14:15:00 GMThttp://www.shnenglu.com/sigepluto/archive/2010/03/26/110622.htmlhttp://www.shnenglu.com/sigepluto/comments/110622.htmlhttp://www.shnenglu.com/sigepluto/archive/2010/03/26/110622.html#Feedback3http://www.shnenglu.com/sigepluto/comments/commentRss/110622.htmlhttp://www.shnenglu.com/sigepluto/services/trackbacks/110622.html 

上次说日本v啸警报的时候,E序出错。在解析代码的时候,发现?jin)MFC中的一个Bug?/p>

一。问题的产生?/p>

q个E序Q用来处理日本各U天气预报数据,包括灑֮的预报。如果地震,台风之类的自然灾宛_来,E序?x)把预报数据q行处理Q生成相应的警报信息Qƈ在电(sh)视上面显C滚动的字幕来提C。程序本w,是几q前公司的其他h写的。里面有涉及(qing)到文件读写的地方Q有很多地方Q用?jin)MFC中自带的文gdcCStdioFile?/p>

CStdioFileq个文gdc,估计大家都不陌生。这个类的父c,是CFilecRCStdioFilecLw的功能也很单。CStdioFilecL一个成员函数是ReadStringQ函数的定义如下Q?/p>

    virtual LPTSTR ReadString(__out_ecount_z(nMax) LPTSTR lpsz, __in UINT nMax);
    virtual BOOL ReadString(CString& rString);
MSDN定义如下http://msdn.microsoft.com/library/x5t0zfyf(VS.80).aspxQ?pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 650px; padding-right: 5px; height: 118px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px">
BOOL ReadString(CString& rString);
throw( CFileException );
Return Value
A pointer to the buffer containing the text data. NULL if end-of-file was reached without reading any data; or if boolean, FALSE if end-of-file was reached without reading any data.

ReadString函数能直接读取文本中的一行数据到CString中,很方ѝ读到文件结,没有dM数据的时候,q回FALSE。很单的函数Q但恰恰是这个函数有Bug?/p>

E序在处理数据的时候,?x)生成一些(f)时文Ӟ然后?x)读取这些?f)时文件中的数据,d操作Q正是用的CStdioFile的ReadString函数。读取流E很单:(x)

while(dFile.ReadString(Str_temp))
{
    doSomething();
}

当时的现象ؓ(f)Q读取到最后一行,L直接q回FALSEQ怎么也读不出最后一行来。看?jin)看文g的最后一行,包含2176个字W的数据Q没有换行符。没有Q何异常啊。当时没惛_是MFC的BugQ因Z前有q样那样的毛病,多数是预报数据本w有问题Q所以这ơ也是先分析数据?jin)。分析来分析去,没发现这ơ的数据有什么异常。后来发现如果最后一行的文g不是2176个字W,p正常d来。奇?jin)怪了(jin)Q?176也不是什么特D长度啊。实验了(jin)几次后,觉的是在不对劌Ӏ莫非是MFC的BugQ?/p>

二。发现问题所?/p>

军_看看MFC的代码再说。做?jin)个单的试E序Q跟到MFC代码里一看,果然是MFC的问题!试代码如下Q?/p>

    CStdioFile  dFile;
    dFile.Open("text.txt",CFile::modeRead);
    CString str;
    while (dFile.ReadString(str) != FALSE )
    {
        printf("%s", str);
    }
    dFile.Close();

试代码很简单,读text.txt文g中的每一行,然后打印出来。还?176个字W就不行。确定了(jin)不是数据的问题,是MFC代码本n的Bug?/p>

MFC的ReadString代码如下Q(中文是我加的注释Q?/p>

BOOL CStdioFile::ReadString(CString& rString)
{
    ASSERT_VALID(this);
    rString = &afxChNil;    // empty string without deallocating
    const int nMaxSize = 128;  //临时字符串的长度
    LPTSTR lpsz = rString.GetBuffer(nMaxSize);  //保存每次d到的字符串到CString?/span>
    LPTSTR lpszResult;  //指向每次d的字W串
    int nLen = 0;
    for (;;)
    {
        lpszResult = _fgetts(lpsz, nMaxSize+1, m_pStream); //d操作
        rString.ReleaseBuffer();
        // handle error/eof case
        if (lpszResult == NULL && !feof(m_pStream))
        {
            clearerr(m_pStream);
            AfxThrowFileException(CFileException::generic, _doserrno,
                m_strFileName);
        }
        // if string is read completely or EOF
        if (lpszResult == NULL ||
            (nLen = lstrlen(lpsz)) < nMaxSize ||
            lpsz[nLen-1] == '\n')
            break;
        nLen = rString.GetLength();
        lpsz = rString.GetBuffer(nMaxSize + nLen) + nLen; //位置后移
    }
    // remove '\n' from end of string if present
    lpsz = rString.GetBuffer(0);
    nLen = rString.GetLength();
    if (nLen != 0 && lpsz[nLen-1] == '\n') // 最后结果中Q去掉回车符
        rString.GetBufferSetLength(nLen-1); 
    return lpszResult != NULL;  // q里是Bug的关键。返回g对!
}

可以看到QReadString的底层,是用fgets来读取文件的。在内部Q每ơ读?28个字W到CString中,然后位置后移Q反复读?28个字W,直到遇到回RW或者文件结束。最后把回RW去掉,q回一个CString。其中,lpszResult也指向每ơ读出的字符丌Ӏ?/p>

q里q出问题所在了(jin)Q?176个字W,正好?28?7倍!也就是说Q?font color="#ff0000">只要文g最后一行是128倍数个字W,׃定会(x)q回FALSE?/strong>

Z么会(x)q样呢,因ؓ(f)ReadString在每ơ读?28个字W的时候,用lpszResult指向d到的字符丌Ӏ如果读满了(jin)128个字W,ql读Q如果读到的字符不够128个,那么q束读取?/font>

当一行数据正好ؓ(f)128的倍数Q又没有回RW的时候,?x)发生什么呢Q比如最后一行数据是128个,那么Q读一?28个字W,?x)l读下一ơ,但是下一ơ的dQ什么也没有dQlpszResult指向NULLQ最后的q回|是return lpszResult != NULL; 所以返回FALSE?/font>

但之前读到的128个字W,已经在CString里面?jin)?/font>也就是说实际上读取已l成功了(jin)Q但q是q回?jin)FALSE。返回g恰当Q?/font>

Bug的描qͼ(x)当文件的最后一行数据,正好?28的倍数个字W的时候,?/font>ReadStringdQ一定会(x)q回FALSE。但实际上读取是成功的,q回的CString中的数据是正的Q(VC6.0中存在这个BugQVS2005中,没有q个BugQ?/font>

q个BugQ只?x)?jing)响到最后一行数据。因为如果有换行W的存在QlpszResult׃?x)?f)NULL?/font>

三。解x?/font>

要解册个问题,也简单,修改一下判断ReadString成功与否的语句:(x)

while (dFile.ReadString(str) != FALSE || str.GetLength() != 0)

在返回FALSE的情况下QCString的长度不?Q就不算dp|。或者这?

if(!dFile.ReadString(str) && str.GetLength() == 0)

在返回FALSEq且CString的长度ؓ(f)0Q则读取失败,否则是d成功?/p>

q个E序Q是用VC6.0做的Q我有看?jin)看VC2005中的代码Q发现这个Bug被修复了(jin)Q代码如下:(x)

BOOL CStdioFile::ReadString(CString& rString)
{
    ASSERT_VALID(this);
    rString = _T("");    // empty string without deallocating
    const int nMaxSize = 128;
    LPTSTR lpsz = rString.GetBuffer(nMaxSize);
    LPTSTR lpszResult;
    int nLen = 0;
    for (;;)
    {
        lpszResult = _fgetts(lpsz, nMaxSize+1, m_pStream);
        rString.ReleaseBuffer();
        // handle error/eof case
        if (lpszResult == NULL && !feof(m_pStream))
        {
            Afx_clearerr_s(m_pStream);
            AfxThrowFileException(CFileException::genericException, _doserrno,
                m_strFileName);
        }
        // if string is read completely or EOF
        if (lpszResult == NULL ||
            (nLen = (int)lstrlen(lpsz)) < nMaxSize ||
            lpsz[nLen-1] == '\n')
            break;
        nLen = rString.GetLength();
        lpsz = rString.GetBuffer(nMaxSize + nLen) + nLen;
    }
    // remove '\n' from end of string if present
    lpsz = rString.GetBuffer(0);
    nLen = rString.GetLength();
    if (nLen != 0 && lpsz[nLen-1] == '\n')
        rString.GetBufferSetLength(nLen-1);
    return nLen != 0; //q回值变?jin)?/span>
}

我们看到QVC2005中,d部分的代码与VC6.0中的代码完全一栗不一L(fng)地方只是q回值的部分。VC2005的ReadString中,q回gؓ(f)

return nLen != 0;

也就是说Q只要读出的CString的长度不?׃ؓ(f)d成功。与我修改后的方法完全一致。就q样向客戯释,然后修改?jin)。?zhn)剧的是,几年前所有程序中所有用ReadString函数的地方,都要q行修改。。?/p>

MFC的这个Bug比较隐蔽Q^怸Ҏ(gu)发现Q但一旦遇到特D长度的数据Q就?x)表现异常。所以,在用VC6.0开发的时候,量避免使用ReadStringQ或者在使用中,多判断一步读取出来的CString长度。避开q个Bug?/p>

Jakcie 2010-03-26 22:15 发表评论
]]>
虚惊一场的啸http://www.shnenglu.com/sigepluto/archive/2010/03/08/109161.htmlJakcieJakcieSun, 07 Mar 2010 18:07:00 GMThttp://www.shnenglu.com/sigepluto/archive/2010/03/08/109161.htmlhttp://www.shnenglu.com/sigepluto/comments/109161.htmlhttp://www.shnenglu.com/sigepluto/archive/2010/03/08/109161.html#Feedback1http://www.shnenglu.com/sigepluto/comments/commentRss/109161.htmlhttp://www.shnenglu.com/sigepluto/services/trackbacks/109161.html2?7日,智利发生8.8U特大地震,1个世U以来最强的地震Q全球都在关注。其中,日本的反应尤其大。日本本w自然灾害特别多。火山,地震Qv啸,以及(qing)z水。所以,对这U自然灾宛_然的比较敏感。最主要的原因,在于智利的地震,?x)?jing)响到日本Q这是有前R之鉴的?/p>

1960q智利v域发生了(jin)9.5U(太恐怖了(jin)。。。)(j)地震。引起了(jin)啸Q一直穿q整个太qxQ从南美Q一直到东亚。日本,夏威P菲律N?00多hM。所以,q次8.8U地震,如果再来一ơv啸,那可不得?jin)啊。这ơ智利爆发的地震Q引发了(jin)剧烈的v啸。如今,啸的巨正在横q太qxQ直奔日本v岸而来。估计到达日本时Q浪高依然可以达?0-20英尺?/p>

日本全国都在紧急动员防范v啸,?sh)视台在电(sh)视屏幕一角实时展CZq日本地图,所有专安会(x)遭到啸袭击的地区都被标记出来,如今Q从北v?到冲lI整个日本东v岸几乎都变成?jin)一片红艌Ӏ屏q上方则在滚动播出沿各地发布的遉K通知Q例如,青森县已l有一万九(ji)千多戯要求dq入公用遉K?施。日本全国到现在为止已有40万hd家园。整个流E顺畅,井然有序。这一切,一斚w反映?jin)日本在自然灑֮面前的准备工作,另一斚w也反映了(jin)日本?间的恐惧?/p>

q播员在不断在播报各地vq面的增高情况,镜头不时切换到沿岸各圎ͼ报道当地状况和抢险准备的情况Q很多沿公路如东名高速公路已l关闭,h公园停止营业Q船舶纷U入避难\Uѝ经常有dx断播韛_的播报,紧急通报某地^面出现异常增高。{眼间有?jin)一U陷入某场战争的感觉?/p>

发个图,看的比较清楚。整个日本靠太^z的一边,全部是v啸警报?/p>

公司做的目Q正好是l各个电(sh)视台做的天气预报目Q地震台风v啸的预报Q也包含在内。关键时刻,日本?sh)视台打电(sh)话_(d)预报图显C的有误Q只能看到大阪的高Q其他地Ҏ(gu)有浪高。导致只能显C部分的警报图。东京电(sh)视台也打?sh)话说?sh)视上滚动昄的警报文字,用我们的E序处理不了(jin)Q显C出不来。马上ؕ套了(jin)Q当天公司几个h都通宵在处理。最后强制显C全国的警报图?/p>

最后发玎ͼ日本?sh)视台预报图昄有误Q其实是正确的,本来其他地方没有浪高。ؓ(f)什么呢Q因为根本就没那么大的浪Q?/p>

日本气象厅在3??0?5分全面解除太qx沿岸啸警报?
气象厅负责地震v啸检的N在记者会(x)见中谢罪Uͼ“对于啸预测大大过?jin)实际情况,以?qing)警报旉q长表示歉意?#8221;

 

Z么这ơ的地震Q没有引起很大的啸呢?

智利此次地震所引发的v怹h很强的方向性,英国威尔士大学新港学院(University of Wales, NewportQ的Simon Haslett ?#8220;q回的v啔R常有方向性,而不是U均匀向四周传播的‘往池塘里扔矛_’似的波浪”。他表示震中最q的岸Q以?qing)胡安费(dng)南h岛QJuan Fernandez IslandsQv啔R常强Q但是其他方向的啸能量和高度迅速减退?

而且Q地震震源的相对深度?5公里—可能也减小?jin)v床的上升Q而正是v床的上升排挤?jin)v水。英国u敦大学学院Bill McGuire表示“相比?004q的印度z地震,智利地震要更深,释放到地表的能量也更?#8221;?

虚惊一场啊?

至于东京?sh)视台的预报文字处理不出来,l过我一步步DebugQ最后发玎ͼ是MFC的一个Bug造成的!气死我了(jin)。导致所有代码涉?qing)这个Bug的地斚w要修攏V下日志,详细说说q个Bug?/p>

Jakcie 2010-03-08 02:07 发表评论
]]>
鶹þ| þþþþaŷa| XxŷʸƷþþþþ| þ99Ʒһ| ڸþþþþ| 99ƷȾþ| ŷһþ| þۺϾþڹ| 91Ʒþþþþ| þþƷAVӰԺ| þþƷ޾Ʒŷ| þþƷavˮ | þþƷAVһ| þþþùƷŮӰԺ| ŷۺϾþͼƬ| ƬҹƬþ | 㽶þһ޶ӰԺ| yy6080þ| þһ99| 99þþƷѹۿ| ƷƷھþø| þùȾƷҰAV| 㽶þӰԺ| ޵һƷƷþ| ަvþþ| þһѲ| þþƷA㽶 | ĻƷѾþþ| þþþAV鶹| ޾þһ | þþƷۺ| þҹɫƷa| Ʒþþþһ| bƷþþþþþ| þ99Ʒ鶹| þ㽶߿ۿ | ھƷþþӰԺ| ľƷ99þù| þƵ| ˾þþƷavһ| þһ|