﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-行进中开火</title><link>http://www.cppblog.com/sigepluto/</link><description>C++夜未眠</description><language>zh-cn</language><lastBuildDate>Thu, 23 Apr 2026 23:55:26 GMT</lastBuildDate><pubDate>Thu, 23 Apr 2026 23:55:26 GMT</pubDate><ttl>60</ttl><item><title>MFC中一个危险的Bug</title><link>http://www.cppblog.com/sigepluto/archive/2010/03/26/110622.html</link><dc:creator>Jakcie</dc:creator><author>Jakcie</author><pubDate>Fri, 26 Mar 2010 14:15:00 GMT</pubDate><guid>http://www.cppblog.com/sigepluto/archive/2010/03/26/110622.html</guid><wfw:comment>http://www.cppblog.com/sigepluto/comments/110622.html</wfw:comment><comments>http://www.cppblog.com/sigepluto/archive/2010/03/26/110622.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/sigepluto/comments/commentRss/110622.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sigepluto/services/trackbacks/110622.html</trackback:ping><description><![CDATA[
<p>&nbsp;</p> <p>上次说日本海啸警报的时候，程序出错。在解析代码的时候，发现了MFC中的一个Bug。</p> <p>一。问题的产生。</p> <p>这个程序，用来处理日本各种天气预报数据，包括灾害的预报。如果地震，台风之类的自然灾害到来，程序会把预报数据进行处理，生成相应的警报信息，并在电视上面显示滚动的字幕来提示。程序本身，是几年前公司的其他人写的。里面有涉及到文件读写的地方，有很多地方，用了MFC中自带的文件读写类CStdioFile。</p> <p>CStdioFile这个文件读写类，估计大家都不陌生。这个类的父类，是CFile类。CStdioFile类本身的功能也很简单。CStdioFile类有一个成员函数是ReadString，函数的定义如下：</p><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: 58px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">virtual</span> LPTSTR ReadString(__out_ecount_z(nMax) LPTSTR lpsz, __in UINT nMax);
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">virtual</span> BOOL ReadString(CString&amp; rString);</pre></pre>MSDN定义如下<a href="http://msdn.microsoft.com/library/x5t0zfyf(VS.80).aspx">http://msdn.microsoft.com/library/x5t0zfyf(VS.80).aspx</a>：<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"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">BOOL ReadString(CString&amp; rString);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"><span style="color: #0000ff">throw</span>( CFileException );
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">Return Value
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">A pointer to the buffer containing the text data. NULL <span style="color: #0000ff">if</span> end-of-file was reached without reading any data; <span style="color: #0000ff">or</span> <span style="color: #0000ff">if</span> boolean, FALSE <span style="color: #0000ff">if</span> end-of-file was reached without reading any data.</pre></pre>
<p>ReadString函数能直接读取文本中的一行数据到CString中，很方便。读到文件结尾，没有读出任何数据的时候，返回FALSE。很简单的函数，但恰恰是这个函数有Bug。</p>
<p>程序在处理数据的时候，会生成一些临时文件，然后会读取这些临时文件中的数据，读取操作，正是用的CStdioFile的ReadString函数。读取流程很简单：</p><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: 90px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"><span style="color: #0000ff">while</span>(dFile.ReadString(Str_temp))
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">{
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    doSomething();
</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">}</pre></pre>
<p>当时的现象为，读取到最后一行，总是直接返回FALSE，怎么也读不出最后一行来。看了看文件的最后一行，包含2176个字符的数据，没有换行符。没有任何异常啊。当时没想到是MFC的Bug，因为以前有这样那样的毛病，多数是预报数据本身有问题，所以这次也是先分析数据了。分析来分析去，没发现这次的数据有什么异常。后来发现如果最后一行的文件不是2176个字符，就能正常读出来。奇了怪了，2176也不是什么特殊长度啊。实验了几次后，觉的是在不对劲。莫非是MFC的Bug？</p>
<p>二。发现问题所在</p>
<p>决定看看MFC的代码再说。做了个简单的测试程序，跟到MFC代码里一看，果然是MFC的问题！测试代码如下：</p><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: 147px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    CStdioFile  dFile;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    dFile.Open("<span style="color: #8b0000">text.txt</span>",CFile::modeRead);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    CString str;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">while</span> (dFile.ReadString(str) != FALSE )
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        printf("<span style="color: #8b0000">%s</span>", str);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    dFile.Close();
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"></pre></pre>
<p>测试代码很简单，读text.txt文件中的每一行，然后打印出来。还是2176个字符就不行。确定了不是数据的问题，就是MFC代码本身的Bug。</p>
<p>MFC的ReadString代码如下：（中文是我加的注释）</p><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; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">BOOL CStdioFile::ReadString(CString&amp; rString)
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">{
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    ASSERT_VALID(<span style="color: #0000ff">this</span>);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    rString = &amp;afxChNil;    <span style="color: #008000">// empty string without deallocating</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">const</span> <span style="color: #0000ff">int</span> nMaxSize = 128;  <span style="color: #008000">//临时字符串的长度</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    LPTSTR lpsz = rString.GetBuffer(nMaxSize);  <span style="color: #008000">//保存每次读取到的字符串到CString中</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    LPTSTR lpszResult;  <span style="color: #008000">//指向每次读到的字符串</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">int</span> nLen = 0;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">for</span> (;;)
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        lpszResult = _fgetts(lpsz, nMaxSize+1, m_pStream); <span style="color: #008000">//读取操作</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        rString.ReleaseBuffer();
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        <span style="color: #008000">// handle error/eof case</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        <span style="color: #0000ff">if</span> (lpszResult == NULL &amp;&amp; !feof(m_pStream))
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">            clearerr(m_pStream);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">            AfxThrowFileException(CFileException::generic, _doserrno,
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">                m_strFileName);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        <span style="color: #008000">// if string is read completely or EOF</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        <span style="color: #0000ff">if</span> (lpszResult == NULL ||
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">            (nLen = lstrlen(lpsz)) &lt; nMaxSize ||
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">            lpsz[nLen-1] == '\n')
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">            <span style="color: #0000ff">break</span>;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        nLen = rString.GetLength();
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        lpsz = rString.GetBuffer(nMaxSize + nLen) + nLen; <span style="color: #008000">//位置后移</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #008000">// remove '\n' from end of string if present</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    lpsz = rString.GetBuffer(0);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    nLen = rString.GetLength();
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">if</span> (nLen != 0 &amp;&amp; lpsz[nLen-1] == '\n') <span style="color: #008000">// 最后结果中，去掉回车符</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        rString.GetBufferSetLength(nLen-1); 
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">return</span> lpszResult != NULL;  <span style="color: #008000">// 这里就是Bug的关键。返回值不对！</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">}</pre></pre>
<p>可以看到，ReadString的底层，是用fgets来读取文件的。在内部，每次读取128个字符到CString中，然后位置后移，反复读取128个字符，直到遇到回车符或者文件结束。最后把回车符去掉，返回一个CString。其中，lpszResult也指向每次读出的字符串。</p>
<p>这里就看出问题所在了，2176个字符，正好是128的17倍！也就是说，<font color="#ff0000"><strong>只要文件最后一行是128倍数个字符，就一定会返回FALSE。</strong></font></p>
<p><font color="#000000">为什么会这样呢，因为ReadString在每次读取128个字符的时候，用lpszResult指向读取到的字符串。如果读满了128个字符，就继续读，如果读到的字符不够128个，那么就结束读取。</font></p>
<p><font color="#000000">当一行数据正好为128的倍数，又没有回车符的时候，会发生什么呢？比如最后一行数据是128个，那么，读一次128个字符，会继续读下一次，但是下一次的读取，什么也没有读到，lpszResult就指向NULL，最后的返回值，是return lpszResult != NULL; 所以返回FALSE。</font></p>
<p><font color="#000000">但之前读到的128个字符，已经在CString里面了。</font><font color="#ff0000">也就是说实际上读取已经成功了，但还是返回了FALSE。返回值不恰当！</font></p>
<p><font color="#ff0000">Bug的描述：当文件的最后一行数据，正好是128的倍数个字符的时候，用</font><font color="#ff0000">ReadString读取，一定会返回FALSE。但实际上读取是成功的，返回的CString中的数据是正确的！（VC6.0中存在这个Bug，VS2005中，没有这个Bug）</font></p>
<p><font color="#000000">这个Bug，只会影响到最后一行数据。因为如果有换行符的存在，lpszResult就不会为NULL。</font></p>
<p><font color="#000000">三。解决方法</font></p>
<p><font color="#000000">要解决这个问题，也简单，修改一下判断ReadString成功与否的语句：</font></p><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: 42px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"><span style="color: #0000ff">while</span> (dFile.ReadString(str) != <span style="color: #0000ff">FALSE</span> || str.GetLength() != 0)</pre></pre>
<p>在返回FALSE的情况下，CString的长度不为0，就不算读取失败。或者这样:</p><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: 44px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"><span style="color: #0000ff">if</span>(!dFile.ReadString(str) &amp;&amp; str.GetLength() == 0)</pre></pre>
<p>在返回FALSE并且CString的长度为0，则算读取失败，否则就是读取成功。</p>
<p>这个程序，是用VC6.0做的，我有看了看VC2005中的代码，发现这个Bug被修复了，代码如下：</p><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; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">BOOL CStdioFile::ReadString(CString&amp; rString)
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">{
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    ASSERT_VALID(<span style="color: #0000ff">this</span>);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    rString = _T("<span style="color: #8b0000"></span>");    <span style="color: #008000">// empty string without deallocating</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">const</span> <span style="color: #0000ff">int</span> nMaxSize = 128;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    LPTSTR lpsz = rString.GetBuffer(nMaxSize);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    LPTSTR lpszResult;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">int</span> nLen = 0;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">for</span> (;;)
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        lpszResult = _fgetts(lpsz, nMaxSize+1, m_pStream);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        rString.ReleaseBuffer();
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        <span style="color: #008000">// handle error/eof case</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        <span style="color: #0000ff">if</span> (lpszResult == NULL &amp;&amp; !feof(m_pStream))
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        {
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">            Afx_clearerr_s(m_pStream);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">            AfxThrowFileException(CFileException::genericException, _doserrno,
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">                m_strFileName);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        <span style="color: #008000">// if string is read completely or EOF</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        <span style="color: #0000ff">if</span> (lpszResult == NULL ||
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">            (nLen = (<span style="color: #0000ff">int</span>)lstrlen(lpsz)) &lt; nMaxSize ||
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">            lpsz[nLen-1] == '\n')
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">            <span style="color: #0000ff">break</span>;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        nLen = rString.GetLength();
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        lpsz = rString.GetBuffer(nMaxSize + nLen) + nLen;
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    }
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #008000">// remove '\n' from end of string if present</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    lpsz = rString.GetBuffer(0);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    nLen = rString.GetLength();
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">if</span> (nLen != 0 &amp;&amp; lpsz[nLen-1] == '\n')
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">        rString.GetBufferSetLength(nLen-1);
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">    <span style="color: #0000ff">return</span> nLen != 0; <span style="color: #008000">//返回值变了！</span>
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px">}</pre></pre>
<p>我们看到，VC2005中，读取部分的代码与VC6.0中的代码完全一样。不一样的地方只是返回值的部分。VC2005的ReadString中，返回值为</p>
<p>return nLen != 0;</p>
<p>也就是说，只要读出的CString的长度不为0就为读取成功。与我修改后的方法完全一致。就这样向客户解释，然后修改了。悲剧的是，几年前所有程序中所有使用ReadString函数的地方，都要进行修改。。。</p>
<p>MFC的这个Bug比较隐蔽，平常不容易发现，但一旦遇到特殊长度的数据，就会表现异常。所以，在用VC6.0开发的时候，尽量避免使用ReadString，或者在使用中，多判断一步读取出来的CString长度。避开这个Bug。</p><img src ="http://www.cppblog.com/sigepluto/aggbug/110622.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sigepluto/" target="_blank">Jakcie</a> 2010-03-26 22:15 <a href="http://www.cppblog.com/sigepluto/archive/2010/03/26/110622.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>虚惊一场的海啸</title><link>http://www.cppblog.com/sigepluto/archive/2010/03/08/109161.html</link><dc:creator>Jakcie</dc:creator><author>Jakcie</author><pubDate>Sun, 07 Mar 2010 18:07:00 GMT</pubDate><guid>http://www.cppblog.com/sigepluto/archive/2010/03/08/109161.html</guid><wfw:comment>http://www.cppblog.com/sigepluto/comments/109161.html</wfw:comment><comments>http://www.cppblog.com/sigepluto/archive/2010/03/08/109161.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sigepluto/comments/commentRss/109161.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sigepluto/services/trackbacks/109161.html</trackback:ping><description><![CDATA[
<p>2月27日，智利发生8.8级特大地震，1个世纪以来最强的地震！全球都在关注。其中，日本的反应尤其大。日本本身自然灾害特别多。火山，地震，海啸，以及洪水。所以，对这种自然灾害天然的比较敏感。最主要的原因，在于智利的地震，会影响到日本！这是有前车之鉴的。</p> <p>1960年智利海域发生了9.5级（太恐怖了。。。）地震。引起了海啸，一直穿过整个太平洋，从南美，一直到东亚。日本，夏威夷，菲律宾都有200多人死亡。所以，这次8.8级地震，如果再来一次海啸，那可不得了啊。这次智利爆发的地震，引发了剧烈的海啸。如今，海啸的巨浪正在横过太平洋，直奔日本海岸而来。估计到达日本时，浪高依然可以达到10-20英尺。</p> <p>日本全国都在紧急动员防范海啸，电视台在电视屏幕一角实时展示一幅日本地图，所有专家预测会遭到海啸袭击的地区都被标记出来，如今，从北海道 到冲绳，整个日本东海岸几乎都变成了一片红色。屏幕上方则在滚动播出沿海各地发布的避难通知，例如，青森县已经有一万九千多户被要求离家进入公用避难设 施。日本全国到现在为止已有40万人离开家园。整个流程顺畅，井然有序。这一切，一方面反映了日本在自然灾害面前出色的准备工作，另一方面也反映了日本民 间的恐惧。</p> <p>广播员在不断在播报各地海平面的增高情况，镜头不时切换到沿岸各地，报道当地状况和抢险准备的情况，很多沿海公路如东名高速公路已经关闭，海滨公园停止营业，船舶纷纷进入避难路线。经常有画外音插断播音员的播报，紧急通报某地海平面出现异常增高。转眼间就有了一种陷入某场战争的感觉。</p><!--more--> <p>发个图，看的比较清楚。整个日本靠太平洋的一边，全部是海啸警报。</p><a href="http://picasaweb.google.com/lh/photo/c4iVEuWU3D00ysfcm8jyIQ?authkey=Gv1sRgCPrNiYO6gbrXVw&amp;feat=embedwebsite"><img src="http://lh6.ggpht.com/_-4ZKm7IEs2Y/S5Pl5EoyFmI/AAAAAAAABs8/KhZxz3yZb9Q/s800/tsunami12%5B5%5D.jpg"></a>  <p>公司做的项目，正好是给各个电视台做的天气预报项目，地震台风海啸的预报，也包含在内。关键时刻，日本电视台打电话说，预报图显示的有误，只能看到大阪的浪高，其他地方没有浪高。导致只能显示部分的警报图。东京电视台也打电话说电视上滚动显示的警报文字，用我们的程序处理不了，显示出不来。马上乱套了，当天公司几个人都通宵在处理。最后强制显示全国的警报图。</p> <p>最后发现，日本电视台预报图显示有误，其实是正确的，本来其他地方就没有浪高。为什么呢？因为根本就没那么大的浪！</p><a href="http://picasaweb.google.com/lh/photo/bPSxltmMsHTQk_e1Z-iF8w?authkey=Gv1sRgCPrNiYO6gbrXVw&amp;feat=embedwebsite"><img src="http://lh4.ggpht.com/_-4ZKm7IEs2Y/S5Pl6TYjq6I/AAAAAAAABtE/izL_0oxvgaM/s800/clear_tsunami%5B3%5D.png"></a>  <p>日本气象厅在3月1日10点15分全面解除太平洋沿岸海啸警报。 <br>气象厅负责地震海啸检测的课长在记者会见中谢罪称，&#8220;对于海啸预测大大超过了实际情况，以及警报时间过长表示歉意。&#8221;</p> <p>&#160;</p> <p>为什么这次的地震，没有引起很大的海啸呢？</p> <p>智利此次地震所引发的海啸也具有很强的方向性，英国威尔士大学新港学院（University of Wales, Newport）的Simon Haslett 说&#8220;这回的海啸非常有方向性，而不是那种均匀向四周传播的&#8216;往池塘里扔石头&#8217;似的波浪&#8221;。他表示离震中最近的海岸，以及胡安费尔南德斯群岛（Juan Fernandez Islands）海啸非常强，但是其他方向的海啸能量和高度迅速减退。 </p> <p>而且，地震震源的相对深度—35公里—可能也减小了海床的上升，而正是海床的上升排挤了海水。英国伦敦大学学院Bill McGuire表示&#8220;相比比2004年的印度洋地震，智利地震要更深，释放到地表的能量也更少&#8221;。 </p> <p>虚惊一场啊。 </p> <p>至于东京电视台的预报文字处理不出来，经过我一步步Debug，最后发现，是MFC的一个Bug造成的！气死我了。导致所有代码涉及这个Bug的地方都要修改。下篇日志，详细说说这个Bug。</p><img src ="http://www.cppblog.com/sigepluto/aggbug/109161.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sigepluto/" target="_blank">Jakcie</a> 2010-03-08 02:07 <a href="http://www.cppblog.com/sigepluto/archive/2010/03/08/109161.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>快速扩展文件大小</title><link>http://www.cppblog.com/sigepluto/archive/2010/03/03/108814.html</link><dc:creator>Jakcie</dc:creator><author>Jakcie</author><pubDate>Wed, 03 Mar 2010 09:57:00 GMT</pubDate><guid>http://www.cppblog.com/sigepluto/archive/2010/03/03/108814.html</guid><wfw:comment>http://www.cppblog.com/sigepluto/comments/108814.html</wfw:comment><comments>http://www.cppblog.com/sigepluto/archive/2010/03/03/108814.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sigepluto/comments/commentRss/108814.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sigepluto/services/trackbacks/108814.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在实际的开发过程中，我们可能需要在文件生成时就立即将文件更改为指定的大小，以便于后续简化对文件的并发操作，这一点在各类的下载工具中有很好的体现。<br>具体方法有：lseek或者 truncate，在Windows中，可以选择 _lseek 或者 SetEndOfFile。&nbsp;&nbsp;<a href='http://www.cppblog.com/sigepluto/archive/2010/03/03/108814.html'>阅读全文</a><img src ="http://www.cppblog.com/sigepluto/aggbug/108814.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sigepluto/" target="_blank">Jakcie</a> 2010-03-03 17:57 <a href="http://www.cppblog.com/sigepluto/archive/2010/03/03/108814.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux中的时间</title><link>http://www.cppblog.com/sigepluto/archive/2009/11/25/101927.html</link><dc:creator>Jakcie</dc:creator><author>Jakcie</author><pubDate>Wed, 25 Nov 2009 12:27:00 GMT</pubDate><guid>http://www.cppblog.com/sigepluto/archive/2009/11/25/101927.html</guid><wfw:comment>http://www.cppblog.com/sigepluto/comments/101927.html</wfw:comment><comments>http://www.cppblog.com/sigepluto/archive/2009/11/25/101927.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sigepluto/comments/commentRss/101927.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sigepluto/services/trackbacks/101927.html</trackback:ping><description><![CDATA[
<p>&nbsp;&nbsp;&nbsp; 在Windwos中，系统时间的设置很简单，界面操作，通俗易懂。而且设置后，重启，关机都没关系。系统时间会自动保存在Bios的时钟里面，启动计算机的时候，系统会自动在Bios里面取硬件时间，以保证时间的不间断。</p> <p>&nbsp;&nbsp;&nbsp; 但在Linux下，默认情况下，系统时间和硬件时间，并不会自动同步。在Linux运行过程中，系统时间和硬件时间以异步的方式运行，互不干扰。硬件时间的运行，是靠Bios电池来维持，而系统时间，是用CPU tick来维持的。</p> <p>&nbsp;&nbsp;&nbsp; 在系统开机的时候，会自动从Bios中取得硬件时间，设置为系统时间。</p> <p>&nbsp;</p> <p><strong>一.Linux系统时间的设置</strong></p> <p>&nbsp;&nbsp;&nbsp; 在Linux中设置系统时间，可以用date命令：</p> <blockquote> <p>//查看时间</p> <p>[root@localhost ~]# date<br>2008年 12月 12日 星期五 14:44:12 CST</p> <p>//修改时间<br>[root@localhost ~]# date --set "1/1/09 00:01" &lt;== （月/日/年时:分:秒）<br>2009年 01月 01日 星期四 00:01:00 CST </p> <p>//date 有几种时间格式可接受，这样也可以设置时间： </p> <p>[root@localhost ~]# date 012501012009.30&nbsp; &lt;== 月日时分年.秒<br>2009年 01月 25日 星期日 01:01:30 CST</p> <p>&nbsp;</p></blockquote> <p>&nbsp;<strong>二.Linux硬件时间的设置</strong></p> <p>&nbsp;&nbsp;&nbsp; 硬件时间的设置，可以用hwclock或者clock命令。其中，clock和hwclock用法相近，只用一个就 行，只不过clock命令除了支持x86硬件体系外，还支持Alpha硬件体系。</p> <blockquote> <p>//查看硬件时间 可以是用 hwclock ，hwclock --show 或者 hwclock -r</p> <p>[root@localhost ~]# hwclock --show<br>2008年12月12日 星期五 06时52分07秒&nbsp; -0.376932 seconds<br><br>//设置硬件时间 </p> <p>[root@localhost ~]# hwclock --set --date="1/25/09 00:00" &lt;== 月/日/年时:分:秒<br>[root@localhost ~]# hwclock<br>2009年01月25日 星期日 00时00分06秒&nbsp; -0.870868 seconds </p><p>&nbsp;</p></blockquote> <p><strong>三.系统时间和硬件时间的同步</strong></p> <p>&nbsp;&nbsp;&nbsp; 同步系统时间和硬件时间，可以使用hwclock命令。</p> <blockquote> <p>//以系统时间为基准，修改硬件时间</p> <p>[root@localhost ~]# hwclock --systohc &lt;== sys（系统时间）to（写到）hc（Hard Clock）<br>[root@localhost ~]# hwclock -w </p><p>//以硬件时间为基准，修改系统时间</p> <p>[root@localhost ~]# hwclock --hctosys <br>[root@localhost ~]# hwclock -s </p><p>&nbsp;</p></blockquote> <p><strong>四.不同机器之间的时间同步</strong> </p><p>&nbsp;&nbsp;&nbsp; 为了避免主机时间因为长期运作下所导致的时间偏差，进行时间同步(synchronize)的工作是非常必要的。Linux系统下，一般使用ntp服务器来同步不同机器的时间。一台机器，可以同时是ntp服务器和ntp客户机。在网络中，推荐使用像DNS服务器一样分层的时间服务器来同步时间。 </p><p>&nbsp;&nbsp;&nbsp; 同步时间，可以使用ntpdate命令，也可以使用ntpd服务。 </p><p>&nbsp;&nbsp;&nbsp; 使用ntpdate比较简单。格式如下： </p><blockquote> <p>[root@linux ~]# ntpdate [-nv] [NTP IP/hostname]<br>[root@linux ~]# ntpdate 192.168.0.2<br>[root@linux ~]# ntpdate time.ntp.org</p></blockquote> <p>&nbsp;&nbsp;&nbsp; 但这样的同步，只是强制性的将系统时间设置为ntp服务器时间。如果cpu tick有问题，只是治标不治本。所以，一般配合cron命令，来进行定期同步设置。比如，在crontab中添加： </p><blockquote> <p>0 12 * * * * /usr/sbin/ntpdate 192.168.0.1 </p></blockquote> <p>&nbsp;&nbsp;&nbsp;&nbsp; 这样，会在每天的12点整，同步一次时间。ntp服务器为192.168.0.1。 </p><p>&nbsp;&nbsp;&nbsp; 使用ntpd服务，要好于ntpdate加cron的组合。因为，ntpdate同步时间，会造成时间的跳跃，对一些依赖时间的程序和服务会造成影响。比如sleep，timer等。而且，ntpd服务可以在修正时间的同时，修正cpu tick。理想的做法为，在开机的时候，使用ntpdate强制同步时间，在其他时候使用ntpd服务来同步时间。 </p><p>&nbsp;&nbsp;&nbsp; 要注意的是，ntpd 有一个自我保护设置: 如果本机与上源时间相差太大, ntpd 不运行. 所以新设置的时间服务器一定要先 ntpdate 从上源取得时间初值, 然后启动 ntpd服务。ntpd服务 运行后, 先是每64秒与上源服务器同步一次, 根据每次同步时测得的误差值经复杂计算逐步调整自己的时间, 随着误差减小, 逐步增加同步的间隔. 每次跳动, 都会重复这个调整的过程. </p><p>&nbsp; </p><p><strong>五.ntpd服务的设置</strong> </p><p>&nbsp;&nbsp;&nbsp; ntpd服务的相关设置文件如下： </p><blockquote> <p>1./etc/ntp.conf：这个是NTP daemon的主要设文件，也是 NTP 唯一的设定文件。 </p><p>2./usr/share/zoneinfo/:在这个目录下的文件其实是规定了各主要时区的时间设定文件，例如北京地区的时区设定文件在 /usr/share/zoneinfo/Asia/Beijing 就是了。这个目录里面的文件与底下要谈的两个文件(clock 与localtime)是有关系的。 </p><p>3./etc/sysconfig/clock：这个文件其实也不包含在NTP 的 daemon 当中，因为这个是 linux 的主要时区设定文件。每次开机后，Linux 会自动的读取这个文件来设定自己系统所默认要显示的时间。 </p><p>4./etc/localtime：这个文件就是&#8220;本地端的时间配置文件&#8221;。刚刚那个clock 文件里面规定了使用的时间设置文件(ZONE) 为 /usr/share/zoneinfo/Asia/Beijing ，所以说，这就是本地端的时间了，此时， Linux系统就会将Beijing那个文件另存为一份 /etc/localtime文件，所以未来我们的时间显示就会以Beijing那个时间设定文件为准。 </p><p>5. /etc/timezone：系统时区文件 </p><p>&nbsp;</p></blockquote> <p>&nbsp;&nbsp;&nbsp; 下面重点说说 /etc/ntp.conf文件的设置。在 NTP Server 的设定上面，其实最好不要对 Internet 无限制的开放，尽量仅提供您自己内部的 Client 端联机进行网络校时就好。此外， NTP Server 总也是需要网络上面较为准确的主机来自行更新自己的时间啊，所以在我们的 NTP Server 上面也要找一部最靠近自己的 Time Server 来进行自我校正。事实上， NTP 这个服务也是 Server/Client 的一种模式。 </p><blockquote> <p>[root@linux ~]# vi /etc/ntp.conf <br># 1. 关于权限设定部分 <br>#　　 权限的设定主要以 restrict 这个参数来设定，主要的语法为： <br># 　　restrict IP mask netmask_IP parameter <br># 　　其中 IP 可以是软件地址，也可以是 default ，default 就类似 0.0.0.0 <br>#　　 至于 paramter 则有： <br>#　　　ignore　：关闭所有的 NTP 联机服务 <br>#　　　nomodify：表示 Client 端不能更改 Server 端的时间参数，不过，  </p><p>#　　　Client 端仍然可以透过 Server 端来进行网络校时。 <br>#　　　notrust ：该 Client 除非通过认证，否则该 Client 来源将被视为不信任网域 <br>#　　　noquery ：不提供 Client 端的时间查询  </p><p>#　　　notrap ：不提供trap这个远程事件登入  </p><p>#　　如果 paramter 完全没有设定，那就表示该 IP (或网域)&#8220;没有任何限制&#8221;  </p><p>restrict default nomodify notrap noquery　# 关闭所有的 NTP 要求封包 <br>restrict 127.0.0.1　　　 #这是允许本级查询<br>restrict 192.168.0.1 mask 255.255.255.0 nomodify <br>#在192.168.0.1/24网段内的服务器就可以通过这台NTP Server进行时间同步了 <br># 2. 上层主机的设定 <br>#　　要设定上层主机主要以 server 这个参数来设定，语法为：<br>#　　server [IP|HOST Name] [prefer]<br>#　　Server 后面接的就是我们上层 Time Server 啰！而如果 Server 参数 <br>#　　后面加上 perfer 的话，那表示我们的 NTP 主机主要以该部主机来作为 <br>#　　时间校正的对应。另外，为了解决更新时间封包的传送延迟动作， <br>#　　所以可以使用 driftfile 来规定我们的主机 <br>#　　在与 Time Server 沟通时所花费的时间，可以记录在 driftfile&nbsp; <br>#　　后面接的文件内，例如下面的范例中，我们的 NTP server 与&nbsp; <br>#　　cn.pool.ntp.org联机时所花费的时间会记录在 /etc/ntp/drift文件内 <br>server 0.pool.ntp.org  </p><p>server 1.pool.ntp.org  </p><p>server 2.pool.ntp.org  </p><p>server cn.pool.ntp.org prefer  </p><p>#其他设置值，以系统默认值即可  </p><p>server&nbsp; 127.127.1.0&nbsp;&nbsp;&nbsp;&nbsp; # local clock  </p><p>fudge&nbsp;&nbsp; 127.127.1.0 stratum 10  </p><p>driftfile /var/lib/ntp/drift<br>broadcastdelay&nbsp; 0.008<br>keys /etc/ntp/keys</p></blockquote> <p>总结一下，restrict用来设置访问权限，server用来设置上层时间服务器，driftfile用来设置保存漂移时间的文件。 </p><p>&nbsp; </p><p><strong>六.ntp服务的启动与观察</strong> </p><p>在启动NTP服务前，先对提供服务的这台主机手动的校正一次时间咯。（因为启动服务器，端口会被服务端占用，就不能手动同步时间了） </p><p>[root@linux ~] # ntpdate cn.pool.ntp.org </p><p>25 Apr 14:33:51 ntpdate[8310]: step time server 80.85.129.2 offset 6.655976 sec </p><p> 然后，启动ntpd服务： </p><p> [root@linux ~] # service ntpd start </p><p>或 [root@linux ~] # /etc/init.d/ntpd start </p><p> 查看端口： </p><p>[root@linux ~] # netstat -ln|grep 123 </p><p>udp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 192.168.228.153:123&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.0.0.0:* </p><p>udp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 127.0.0.1:123&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.0.0.0:* </p><p>udp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 0.0.0.0:123&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.0.0.0:* </p><p>udp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 :::123&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :::* </p><p>如何确认我们的NTP服务器已经更新了自己的时间呢？ </p><p>[root@linux ~] # ntpstat </p><p>synchronized to NTP server(127.127.1.0) at stratum 11 </p><p>time correct to within 950ms </p><p>polling server every 64 s </p><p>#改指令可列出NTP服务器是否与上层联机。由上述输出结果可知，时间校正约 </p><p>#为950*10(-6)秒。且每隔64秒会主动更新时间。 </p><p>常见的错误： </p><p>25 Apr 15:30:17 ntpdate[11520]: no server suitable for synchronization found </p><p>其实，这不是一个错误。而是由于每次重启NTP服务器之后大约要3－5分钟客户端才能与server建立正常的通讯连接。当此时用客户端连接服务端就会报这样的信息。一般等待几分钟就可以了。 </p><p>[root@linux ~] # ntptrace &#8211;n 127.0.0.1 </p><p>127.0.0.1:stratum 11, offset 0.000000，synch distance 0.950951 </p><p>222.73.214.125：stratum 2，offset &#8211;0.000787，synch distance 0.108575 </p><p>209.81.9.7:stratum 1，offset 0.000028，synch distance 0.00436，refid &#8216;GPS&#8217; </p><p>#这个指令可以列出目前NTP服务器（第一层）与上层NTP服务器（第二层）彼此之间的 </p><p>#关系 </p><p>[root@linux ~] # ntpq &#8211;p </p><p><img alt="" src="http://1843.img.pp.sohu.com.cn/images/blog/2008/9/14/15/21/11d06a131b3g215.jpg" border="0"> </p><p>指令&#8220;ntpq -p&#8221;可以列出目前我们的NTP与相关的上层NTP的状态，以上的几个字段的意义如下： </p><p>remote：即NTP主机的IP或主机名称。注意最左边的符号，如果由&#8220;+&#8221;则代表目前正在作用钟的上层NTP，如果是&#8220;*&#8221;则表示也有连上线，不过是作为次要联机的NTP主机。 </p><p>refid：参考的上一层NTP主机的地址 </p><p>st：即stratum阶层 </p><p>when：几秒前曾做过时间同步更新的操作 </p><p>poll：下次更新在几秒之后 </p><p>reach：已经向上层NTP服务器要求更新的次数 </p><p>delay：网络传输过程钟延迟的时间 </p><p>offset：时间补偿的结果 </p><p>jitter：Linux系统时间与BIOS硬件时间的差异时间 </p><p>&nbsp; </p><p>&nbsp;&nbsp;&nbsp; 最后提及一点，ntp服务，默认只会同步系统时间。如果想要让ntp同时同步硬件时间，可以设置/etc/sysconfig/ntpd 文件。 </p><p>在/etc/sysconfig/ntpd文件中，添加 SYNC_HWCLOCK=yes 这样，就可以让硬件时间与系统时间一起同步。</p><img src ="http://www.cppblog.com/sigepluto/aggbug/101927.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sigepluto/" target="_blank">Jakcie</a> 2009-11-25 20:27 <a href="http://www.cppblog.com/sigepluto/archive/2009/11/25/101927.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windwos7初体验</title><link>http://www.cppblog.com/sigepluto/archive/2008/11/11/66622.html</link><dc:creator>Jakcie</dc:creator><author>Jakcie</author><pubDate>Tue, 11 Nov 2008 09:50:00 GMT</pubDate><guid>http://www.cppblog.com/sigepluto/archive/2008/11/11/66622.html</guid><wfw:comment>http://www.cppblog.com/sigepluto/comments/66622.html</wfw:comment><comments>http://www.cppblog.com/sigepluto/archive/2008/11/11/66622.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sigepluto/comments/commentRss/66622.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sigepluto/services/trackbacks/66622.html</trackback:ping><description><![CDATA[<p>今天图个新鲜，在虚拟机里面安装了Windwos7玩了玩，说说感受。<br></p>
<p>虚拟机我用的是Vmware Workstation6.5，官方下载可以试用30天。其实现在Vmware Server和Vmware Player都可以免费使用，方便的很。设置了1Gb的内存，16Gb的硬盘，我这里，用的是SCSI的硬盘，但在网上看到有人安装不了，必须选择IDE的才能安装。也许是VMware的版本问题吧。<br></p>
<p>Windows7的安装过程比Vista和XP简化了不少，速度也不慢，我开这一堆东西，同时安装的，也没觉的等太久。<br></p>
<p>第一感觉，很像Vista，但去除了Vista的UAC，很多地方，虽然有那个安全标志（那个黄色的小盾牌），但并不要用户再次确认。而且，去除一些警告也方便了很多。看来微软也吸取教训了。总体感觉不错，是个Vista++。<img height=768 alt="" src="http://www.cppblog.com/images/cppblog_com/sigepluto/windows7.jpg" width=1024 border=0><br></p>
<p>值得一提的是，Windows7里面的PowerShell，真的很强大！而且貌似连linux下的命令也全包括进去了。有前途！<img height=582 alt="" src="http://www.cppblog.com/images/cppblog_com/sigepluto/powershell.png" width=881 border=0><br></p>
<p>安装完成后，Vmware Tools也可以顺利安装。所有硬件都没有问题。兼容性不错。<br></p>
<p>在安装快结束的时候会遇到要求输入序列号（Product Key）的一步。在这里什么也不填，直接next，应该也可以安装。进系统后，在用网上流传的激活方法激活。但在网上看到有些人在这一步进不了系统，这样，就需要一个可以安装的序列号。需要的朋友，给我写mail，我发给你们。不过尽管如此，也只有30天的试用期。（之后可以续3次）<br></p>
<p>总体感觉Windows7还是很不错的，吸收了Vista的优点，改正了使用不方便的缺点。值得一提的是，Windows7的硬件需求相当低，未来还面向于NetBook。我在虚拟机下一路默认安装下来，只占了5.2Gb的空间。非常不错。</p>
<img src ="http://www.cppblog.com/sigepluto/aggbug/66622.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sigepluto/" target="_blank">Jakcie</a> 2008-11-11 17:50 <a href="http://www.cppblog.com/sigepluto/archive/2008/11/11/66622.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转载：C++库大汇</title><link>http://www.cppblog.com/sigepluto/archive/2008/07/31/57568.html</link><dc:creator>Jakcie</dc:creator><author>Jakcie</author><pubDate>Wed, 30 Jul 2008 16:30:00 GMT</pubDate><guid>http://www.cppblog.com/sigepluto/archive/2008/07/31/57568.html</guid><wfw:comment>http://www.cppblog.com/sigepluto/comments/57568.html</wfw:comment><comments>http://www.cppblog.com/sigepluto/archive/2008/07/31/57568.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sigepluto/comments/commentRss/57568.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sigepluto/services/trackbacks/57568.html</trackback:ping><description><![CDATA[<p>转载：C++库大汇<br><br>&nbsp;&nbsp; 基础类<br>1、 Dinkumware C++ Library <br>参考站点：[url=http://www.dinkumware.com/]http://www.dinkumware.com[/url]<br>P.J. Plauger编写的高品质的标准库。P.J. Plauger博士是Dr. Dobb's程序设计杰出奖的获得者。其编写的库长期被Microsoft采用，并且最近Borland也取得了其OEM的license，在其C/C+ +的产品中采用Dinkumware的库。 <br>2、 RogueWave Standard C++ Library <br>参考站点：[url=http://www.roguewave.com/]http://www.roguewave.com[/url]<br>这个库在Borland C++ Builder的早期版本中曾经被采用，后来被其他的库给替换了。笔者不推荐使用。 <br>3、SGI STL <br>参考站点：[url=http://www.roguewave.com/]http://www.roguewave.com[/url]<br>SGI公司的C++标准模版库。 <br>4、STLport <br>参考站点：[url=http://www.stlport.org/]http://www.stlport.org[/url]<br>SGI STL库的跨平台可移植版本。 <br>5、准标准库——Boost <br>Boost 库是一个经过千锤百炼、可移植、提供源代码的C++库，作为标准库的后备，是C++标准化进程的发动机之一。 Boost库由C++标准委员会库工作组成员发起，在C++社区中影响甚大，其成员已近2000人。 Boost库为我们带来了最新、最酷、最实用的技术，是不折不扣的"准"标准库。 <br>Boost中比较有名气的有这么几个库： <br>Regex <br>正则表达式库 <br>Spirit <br>LL parser framework，用C++代码直接表达EBNF <br>Graph <br>图组件和算法 <br>Lambda <br>在调用的地方定义短小匿名的函数对象，很实用的functional功能 <br>Concept check <br>检查泛型编程中的concept <br>MPL <br>用模板实现的元编程框架 <br>Thread <br>可移植的C++多线程库 <br>Python <br>把C++类和函数映射到Python之中 <br>Pool <br>内存池管理 <br>Smart_ptr <br>5个智能指针，学习智能指针必读，一份不错的参考是来自CUJ的文章： <br>Smart Pointers in Boost,哦，这篇文章可以查到，CUJ是提供在线浏览的。中文版见笔者在《Dr. Dobb's Journal软件研发杂志》第7辑上的译文。 <br>Boost 总体来说是实用价值很高，质量很高的库。并且由于其对跨平台的强调，对标准C++的强调，是编写平台无关，现代C++的开发者必备的工具。但是Boost 中也有很多是实验性质的东西，在实际的开发中实用需要谨慎。并且很多Boost中的库功能堪称对语言功能的扩展，其构造用尽精巧的手法，不要贸然的花费时 间研读。Boost另外一面，比如Graph这样的库则是具有工业强度，结构良好，非常值得研读的精品代码，并且也可以放心的在产品代码中多多利用。 <br>参考站点：[url=http://www.boost.org/]http://www.boost.org[/url]（国内镜像： [url=http://www.c-view.org/tech/lib/boost/index.htm]http://www.c- view.org/tech/lib/boost/index.htm[/url]） <br>&nbsp;&nbsp; GUI <br>在众多C++的库中，GUI部分的库算是比较繁荣，也比较引人注目的。在实际开发中，GUI库的选择也是非常重要的一件事情，下面我们综述一下可选择的GUI库，各自的特点以及相关工具的支持。 <br>1) MFC <br>大名鼎鼎的微软基础类库（Microsoft Foundation Class）。大凡学过VC++的人都应该知道这个库。虽然从技术角度讲，MFC是不大漂亮的，但是它构建于Windows API 之上，能够使程序员的工作更容易,编程效率高，减少了大量在建立 Windows 程序时必须编写的代码，同时它还提供了所有一般 C++ 编程的优点，例如继承和封装。MFC 编写的程序在各个版本的Windows操作系统上是可移植的，例如，在 Windows 3.1下编写的代码可以很容易地移植到 Windows NT 或 Windows 95 上。但是在最近发展以及官方支持上日渐势微。 <br>2) QT <br>参考网站：[url=http://www.trolltech.com/]http://www.trolltech.com[/url]<br>Qt 是Trolltech公司的一个多平台的C++图形用户界面应用程序框架。它提供给应用程序开发者建立艺术级的图形用户界面所需的所用功能。Qt是完全面 向对象的很容易扩展，并且允许真正地组件编程。自从1996年早些时候，Qt进入商业领域，它已经成为全世界范围内数千种成功的应用程序的基础。Qt也是 流行的Linux桌面环境KDE 的基础，同时它还支持Windows、Macintosh、Unix/X11等多种平台。 <br>3) WxWindows <br>参考网站：[url=http://www.wxwindows.org/]http://www.wxwindows.org[/url]<br>跨平台的GUI库。因为其类层次极像MFC，所以有文章介绍从MFC到WxWindows的代码移植以实现跨平台的功能。通过多年的开发也是一个日趋完善 的 GUI库，支持同样不弱于前面两个库。并且是完全开放源代码的。新近的C++ Builder X的GUI设计器就是基于这个库的。 <br>4) Fox <br>开放源代码的GUI库。作者从自己亲身的开发经验中得出了一个理想的GUI库应该是什么样子的感受出发，从而开始了对这个库的开发。有兴趣的可以尝试一下。 <br>参考网站：[url=http://www.fox-toolkit.org/]http://www.fox-toolkit.org/[/url] <br>5)&nbsp;&nbsp; WTL <br>基于ATL的一个库。因为使用了大量ATL的轻量级手法，模板等技术，在代码尺寸，以及速度优化方面做得非常到位。主要面向的使用群体是开发COM轻量级供网络下载的可视化控件的开发者。 <br>6)&nbsp;&nbsp; GTK <br>参考网站：[url=http://gtkmm.sourceforge.net/]http://gtkmm.sourceforge.net/[/url] <br>GTK是一个大名鼎鼎的C的开源GUI库。在Linux世界中有Gnome这样的杀手应用。而GTK就是这个库的C++封装版本。 <br>&nbsp;&nbsp; 网络通信 <br>1) ACE <br>参考网站：[url=http://www.cs.wustl.edu/~schmidt/ACE.html]http://www.cs.wustl.edu/~schmidt/ACE.html[/url] <br>C++库的代表，超重量级的网络通信开发框架。ACE自适配通信环境（Adaptive Communication Environment）是可以自由使用、开放源代码的面向对象框架，在其中实现了许多用于并发通信软件的核心模式。ACE提供了一组丰富的可复用C++ 包装外观（Wrapper Facade）和框架组件，可跨越多种平台完成通用的通信软件任务，其中包括：事件多路分离和事件处理器分派、信号处理、服务初始化、进程间通信、共享内 存管理、消息路由、分布式服务动态（重）配置、并发执行和同步，等等。 <br>2) StreamModule <br>参考网站：[url=http://www.omnifarious.org/StrMod/]http://www.omnifarious.org/StrMod/[/url] <br>设计用于简化编写分布式程序的库。尝试着使得编写处理异步行为的程序更容易，而不是用同步的外壳包起异步的本质。 <br>3) SimpleSocket <br>参考网站：[url=http://home.hetnet.nl/~lcbokkers/simsock.htm]http://home.hetnet.nl/~lcbokkers/simsock.htm[/url] <br>这个类库让编写基于socket的客户/服务器程序更加容易。 <br>4) A Stream Socket API for C++ <br>参考网站：[url=http://www.pcs.cnu.edu/~dgame/sockets/socketsC++ /sockets.html]http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.html[/url] <br>又一个对Socket的封装库。 <br>&nbsp;&nbsp; XML <br>1) Xerces <br>参考网站：[url=http://xml.apache.org/xerces-c/]http://xml.apache.org/xerces-c/[/url] <br>Xerces-C++ 是一个非常健壮的XML解析器，它提供了验证，以及SAX和DOM API。XML验证在文档类型定义(Document Type Definition，DTD)方面有很好的支持，并且在2001年12月增加了支持W3C XML Schema 的基本完整的开放标准。 <br>2) XMLBooster <br>参考网站：[url=http://www.xmlbooster.com/]http://www.xmlbooster.com/[/url] <br>这个库通过产生特制的parser的办法极大的提高了XML解析的速度，并且能够产生相应的GUI程序来修改这个parser。在DOM和SAX两大主流XML解析办法之外提供了另外一个可行的解决方案。 <br>3) Pull Parser <br>参考网站：[url=http://www.extreme.indiana.edu/xgws/xsoap/xpp/]http://www.extreme.indiana.edu/xgws/xsoap/xpp/[/url] <br>这个库采用pull方法的parser。在每个SAX的parser底层都有一个pull的parser，这个xpp把这层暴露出来直接给大家使用。在要充分考虑速度的时候值得尝试。 <br>4) Xalan <br>参考网站：[url=http://xml.apache.org/xalan-c/]http://xml.apache.org/xalan-c/[/url] <br>Xalan是一个用于把XML文档转换为HTML，纯文本或者其他XML类型文档的XSLT处理器。 <br>5) CMarkup <br>参考网站：[url=http://www.firstobject.com/xml.htm'&gt;[url]http: //www.firstobject.com/xml.htm[/url]]http://www.firstobject.com/xml.htm'&gt;[url]http://www.firstobject.com/xml.htm[/url][/url] <br>这是一种使用EDOM的XML解析器。在很多思路上面非常灵活实用。值得大家在DOM和SAX之外寻求一点灵感。 <br>6) libxml++ <br>[url=http://libxmlplusplus.sourceforge.net/]http://libxmlplusplus.sourceforge.net/[/url] <br>libxml++是对著名的libxml XML解析器的C++封装版本 <br>&nbsp;&nbsp; 科学计算 <br>1) Blitz++ <br>参考网站：[url=http://www.oonumerics.org/blitz/]http://www.oonumerics.org/blitz/[/url] <br>Blitz++ 是一个高效率的数值计算函数库，它的设计目的是希望建立一套既具像C++ 一样方便，同时又比Fortran速度更快的数值计算环境。通常，用C++所写出的数值程序，比 Fortran慢20%左右，因此Blitz++正是要改掉这个缺点。方法是利用C++的template技术，程序执行甚至可以比Fortran更快。 Blitz++目前仍在发展中，对于常见的SVD，FFTs，QMRES等常见的线性代数方法并不提供，不过使用者可以很容易地利用Blitz++所提供 的函数来构建。 <br>2) POOMA <br>参考网站：[url=http://www.codesourcery.com/pooma/pooma]http://www.codesourcery.com/pooma/pooma[/url] <br>POOMA是一个免费的高性能的C++库，用于处理并行式科学计算。POOMA的面向对象设计方便了快速的程序开发，对并行机器进行了优化以达到最高的效率，方便在工业和研究环境中使用。 <br>3) MTL <br>参考网站：[url=http://www.osl.iu.edu/research/mtl/]http://www.osl.iu.edu/research/mtl/[/url] <br>Matrix Template Library(MTL)是一个高性能的泛型组件库，提供了各种格式矩阵的大量线性代数方面的功能。在某些应用使用高性能编译器的情况下，比如Intel的编译器，从产生的汇编代码可以看出其与手写几乎没有两样的效能。 <br>4) CGAL<br>参考网站：[url=http://www.cgal.org/]www.cgal.org[/url] <br>Computational Geometry Algorithms Library的目的是把在计算几何方面的大部分重要的解决方案和方法以C++库的形式提供给工业和学术界的用户。 <br>&nbsp;&nbsp; 游戏开发 <br>1) Audio/Video 3D C++ Programming Library <br>参考网站：[url=http://www.galacticasoftware.com/products/av/]http://www.galacticasoftware.com/products/av/[/url] <br>AV3D是一个跨平台，高性能的C++库。主要的特性是提供3D图形，声效支持（SB,以及S3M），控制接口（键盘，鼠标和遥感），XMS。 <br>2) KlayGE <br>参考网站：[url=http://home.g365.net/enginedev/]http://home.g365.net/enginedev/[/url] <br>国内游戏开发高手自己用C++开发的游戏引擎。KlayGE是一个开放源代码、跨平台的游戏引擎，并使用Python作脚本语言。KlayGE在LGPL协议下发行。感谢龚敏敏先生为中国游戏开发事业所做出的贡献。 <br>3) OGRE <br>参考网站：[url=http://www.ogre3d.org/]http://www.ogre3d.org[/url] <br>OGRE （面向对象的图形渲染引擎）是用C++开发的，使用灵活的面向对象3D引擎。它的目的是让开发者能更方便和直接地开发基于3D硬件设备的应用程序或游戏。 引擎中的类库对更底层的系统库（如：Direct3D和OpenGL）的全部使用细节进行了抽象，并提供了基于现实世界对象的接口和其它类。 <br>&nbsp;&nbsp; 线程 <br>1) C++ Threads <br>参考网站：[url=http://threads.sourceforge.net/]http://threads.sourceforge.net/[/url] <br>这个库的目标是给程序员提供易于使用的类，这些类被继承以提供在Linux环境中很难看到的大量的线程方面的功能。 <br>2) ZThreads<br>参考网站：[url=http://zthread.sourceforge.net/]http://zthread.sourceforge.net/[/url] <br>一个先进的面向对象，跨平台的C++线程和同步库。 <br>&nbsp;&nbsp; 序列化 <br>1) s11n <br>参考网站：[url=http://s11n.net/]http://s11n.net/[/url] <br>一个基于STL的C++库，用于序列化POD，STL容器以及用户定义的类型。 <br>2) Simple XML Persistence Library <br>参考网站：[url=http://sxp.sourceforge.net/]http://sxp.sourceforge.net/[/url] <br>这是一个把对象序列化为XML的轻量级的C++库。 <br>&nbsp;&nbsp; 字符串 <br>1) C++ Str Library <br>参考网站：[url=http://www.utilitycode.com/str/]http://www.utilitycode.com/str/[/url] <br>操作字符串和字符的库，支持Windows和支持gcc的多种平台。提供高度优化的代码，并且支持多线程环境和Unicode，同时还有正则表达式的支持。 <br>2) Common Text Transformation Library <br>参考网站：[url=http://cttl.sourceforge.net/]http://cttl.sourceforge.net/[/url] <br>这是一个解析和修改STL字符串的库。CTTL substring类可以用来比较，插入，替换以及用EBNF的语法进行解析。 <br>3) GRETA <br>参考网站：[url=http://research.microsoft.com/projects/greta/]http://research.microsoft.com/projects/greta/[/url] <br>这是由微软研究院的研究人员开发的处理正则表达式的库。在小型匹配的情况下有非常优秀的表现。 <br>&nbsp;&nbsp; 综合 <br>1) P::Classes <br>参考网站：[url=http://pclasses.com/]http://pclasses.com/[/url] <br>一个高度可移植的C++应用程序框架。当前关注类型和线程安全的signal/slot机制，i/o系统包括基于插件的网络协议透明的i/o架构，基于插件的应用程序消息日志框架，访问sql数据库的类等等。 <br>2) ACDK - Artefaktur Component Development Kit <br>参考网站：[url=http://acdk.sourceforge.net/]http://acdk.sourceforge.net/[/url] <br>这是一个平台无关的C++组件框架，类似于Java或者.NET中的框架（反射机制，线程，Unicode，废料收集，I/O，网络，实用工具，XML，等等），以及对Java, Perl, Python, TCL, Lisp, COM 和 CORBA的集成。 <br>3) dlib C++ library <br>参考网站：[url=http://www.cis.ohio-state.edu/~kingd/dlib/]http://www.cis.ohio-state.edu/~kingd/dlib/[/url] <br>各种各样的类的一个综合。大整数，Socket，线程，GUI，容器类,以及浏览目录的API等等。 <br>4) Chilkat C++ Libraries <br>参考网站：[url=http://www.c'&gt;[url]http://www.c[/url]'&gt;[url]http: //www.c[/url]'&gt;[url]http://www.chilkatsoft.com/cpp_libraries.asp[/url]]http://www.c'&gt;[url]http://www.c[/url]'&gt;[url]http://www.c[/url]'&gt;[url]http://www.chilkatsoft.com/cpp_libraries.asp[/url][/url] <br>这是提供zip，e-mail，编码，S/MIME，XML等方面的库。 <br>5) C++ Portable Types Library (PTypes) <br>参 考网站：[url=http://www.melikyan.com/ptypes/'&gt;[url]http: //www.melikyan.com/ptypes/[/url]]http://www.melikyan.com/ptypes/'&gt;[url]http://www.melikyan.com/ptypes/[/url][/url] <br>这是STL的比较简单的替代品，以及可移植的多线程和网络库。 <br>6) LFC <br>参考网站：[url=http://lfc.sourceforge.net/]http://lfc.sourceforge.net/[/url] <br>哦，这又是一个尝试提供一切的C++库 <br>&nbsp;&nbsp; 其他库 <br>1) Loki <br>参考网站：[url=http://www.moderncppdesign.com/]http://www.moderncppdesign.com/[/url] <br>哦，你可能抱怨我早该和Boost一起介绍它，一个实验性质的库。作者在loki中把C++模板的功能发挥到了极致。并且尝试把类似设计模式这样思想层面的东西通过库来提供。同时还提供了智能指针这样比较实用的功能。 <br>2) ATL <br>ATL(Active Template Library)是一组小巧、高效、灵活的类，这些类为创建可互操作的COM组件提供了基本的设施。 <br>3) FC++: The Functional C++ Library <br>这 个库提供了一些函数式语言中才有的要素。属于用库来扩充语言的一个代表作。如果想要在OOP之外寻找另一分的乐趣，可以去看看函数式程序设计的世界。大师 Peter Norvig在 "Teach Yourself Programming in Ten Years"一文中就将函数式语言列为至少应当学习的6类编程语言之一。 <br>4) FACT! <br>参考网站：[url=http://www.kfa-juelich.de/zam/FACT/start/index.html]http://www.kfa-juelich.de/zam/FACT/start/index.html[/url] <br>另外一个实现函数式语言特性的库 <br>5) Crypto++ <br>提供处理密码，消息验证，单向hash，公匙加密系统等功能的免费库。 <br>还有很多非常激动人心或者是极其实用的C++库，限于我们的水平以及文章的篇幅不能包括进来。在对于这些已经包含近来的库的介绍中，由于并不是每一个我们都使用过，所以难免有偏颇之处，请读者见谅。 <br>6) Managed C++ wrapper for ZLib<br>压缩组件Zlib的C++类库<br>7) CppSQLite - C++ Wrapper for SQLite<br>SQLite C++封装库<br>8)CxImage<br>图像格式转换<br>&nbsp;&nbsp; 资源网站 <br>正如我们可以通过计算机历史上的重要人物了解计算机史的发展，C++相关人物的网站也可以使我们得到最有价值的参考与借鉴，下面的人物我们认为没有介绍的 必要，只因下面的人物在C++领域的地位众所周知，我们只将相关的资源进行罗列以供读者学习，他们有的工作于贝尔实验室，有的工作于知名编译器厂商，有的 在不断推进语言的标准化，有的为读者撰写了多部千古奇作...... <br>Bjarne Stroustrup [url=http://www.research.att.com/~bs/]http://www.research.att.com/~bs/[/url] <br>Stanley B. Lippman http: //blogs.msdn.com/slippman/(中文版[url=http://www.zengyihome.net/slippman /index.htm]http://www.zengyihome.net/slippman/index.htm[/url]) <br>Scott Meyers [url=http://www.aristeia.com/]http://www.aristeia.com/[/url] <br>David Musser [url=http://www.cs.rpi.edu/~musser/]http://www.cs.rpi.edu/~musser/[/url] <br>Bruce Eckel [url=http://www.bruceeckel.com/]http://www.bruceeckel.com[/url] <br>Nicolai M. Josuttis [url=http://www.josuttis.com/]http://www.josuttis.com/[/url] <br>Herb Sutter [url=http://www.gotw.ca/]http://www.gotw.ca/[/url] <br>Andrei Alexandrescu [url=http://www.moderncppdesign.com/]http://www.moderncppdesign.com/[/url] <img src ="http://www.cppblog.com/sigepluto/aggbug/57568.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sigepluto/" target="_blank">Jakcie</a> 2008-07-31 00:30 <a href="http://www.cppblog.com/sigepluto/archive/2008/07/31/57568.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>