﻿<?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>BlogJava-jinfeng_wang-随笔分类-cpp</title><link>http://www.blogjava.net/jinfeng_wang/category/485.html</link><description>G-G-S,D-D-U!</description><language>zh-cn</language><lastBuildDate>Sun, 19 Aug 2007 05:06:22 GMT</lastBuildDate><pubDate>Sun, 19 Aug 2007 05:06:22 GMT</pubDate><ttl>60</ttl><item><title>Using Event Objects (zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/08/17/137579.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 17 Aug 2007 08:20:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/08/17/137579.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/137579.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/08/17/137579.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/137579.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/137579.html</trackback:ping><description><![CDATA[<p>Applications use event objects in a number of situations to notify a waiting thread of the occurrence of an event. For example, overlapped I/O operations on files, named pipes, and communications devices use an event object to signal their completion. For more information about the use of event objects in overlapped I/O operations, see <a href="mk:@MSITStore:D:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001OCT\1033\dllproc.chm::/hh/winbase/synchro_4ur8.htm"><u><font color=#0000ff>Synchronization and Overlapped Input and Output</font></u></a>.</p>
<p>In the following example, an application uses event objects to prevent several threads from reading from a shared memory buffer while a master thread is writing to that buffer. First, the master thread uses the <a href="mk:@MSITStore:D:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001OCT\1033\dllproc.chm::/hh/winbase/synchro_8ub8.htm"><strong><u><font color=#800080>CreateEvent</font></u></strong></a> function to create a manual-reset event object. The master thread sets the event object to nonsignaled when it is writing to the buffer and then resets the object to signaled when it has finished writing. Then it creates several reader threads and an auto-reset event object for each thread. Each reader thread sets its event object to signaled when it is not reading from the buffer. </p>
<pre>#define NUMTHREADS 4
HANDLE hGlobalWriteEvent;
void CreateEventsAndThreads(void)
{
HANDLE hReadEvents[NUMTHREADS], hThread;
DWORD i, IDThread;
// Create a manual-reset event object. The master thread sets
// this to nonsignaled when it writes to the shared buffer.
hGlobalWriteEvent = CreateEvent(
NULL,         // no security attributes
TRUE,         // manual-reset event
TRUE,         // initial state is signaled
"WriteEvent"  // object name
);
if (hGlobalWriteEvent == NULL) {
// error exit
}
// Create multiple threads and an auto-reset event object
// for each thread. Each thread sets its event object to
// signaled when it is not reading from the shared buffer.
for(i = 1; i &lt;= NUMTHREADS; i++)
{
// Create the auto-reset event.
hReadEvents[i] = CreateEvent(
NULL,     // no security attributes
FALSE,    // auto-reset event
TRUE,     // initial state is signaled
NULL);    // object not named
if (hReadEvents[i] == NULL)
{
// Error exit.
}
hThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) ThreadFunction,
&amp;hReadEvents[i],  // pass event handle
0, &amp;IDThread);
if (hThread == NULL)
{
// Error exit.
}
}
}</pre>
<p>Before the master thread writes to the shared buffer, it uses the <a href="mk:@MSITStore:D:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001OCT\1033\dllproc.chm::/hh/winbase/synchro_4f78.htm"><strong><u><font color=#800080>ResetEvent</font></u></strong></a> function to set the state of <code>hGlobalWriteEvent</code> (an application-defined global variable) to nonsignaled. This blocks the reader threads from starting a read operation. The master then uses the <a href="mk:@MSITStore:D:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001OCT\1033\dllproc.chm::/hh/winbase/synchro_9xbn.htm"><strong><u><font color=#800080>WaitForMultipleObjects</font></u></strong></a> function to wait for all reader threads to finish any current read operations. When <strong>WaitForMultipleObjects</strong> returns, the master thread can safely write to the buffer. After it has finished, it sets <code>hGlobalWriteEvent</code> and all the reader-thread events to signaled, enabling the reader threads to resume their read operations. </p>
<pre>VOID WriteToBuffer(VOID)
{
DWORD dwWaitResult, i;
// Reset hGlobalWriteEvent to nonsignaled, to block readers.
if (! ResetEvent(hGlobalWriteEvent) )
{
// Error exit.
}
// Wait for all reading threads to finish reading.
dwWaitResult = WaitForMultipleObjects(
NUMTHREADS,   // number of handles in array
hReadEvents,  // array of read-event handles
TRUE,         // wait until all are signaled
INFINITE);    // indefinite wait
switch (dwWaitResult)
{
// All read-event objects were signaled.
case WAIT_OBJECT_0:
// Write to the shared buffer.
break;
// An error occurred.
default:
printf("Wait error: %d\n", GetLastError());
ExitProcess(0);
}
// Set hGlobalWriteEvent to signaled.
if (! SetEvent(hGlobalWriteEvent) )
{
// Error exit.
}
// Set all read events to signaled.
for(i = 1; i &lt;= NUMTHREADS; i++)
if (! SetEvent(hReadEvents[i]) ) {
// Error exit.
}
}</pre>
<p>Before starting a read operation, each reader thread uses <a href="mk:@MSITStore:D:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001OCT\1033\dllproc.chm::/hh/winbase/synchro_9xbn.htm"><strong><u><font color=#800080>WaitForMultipleObjects</font></u></strong></a> to wait for the application-defined global variable <code>hGlobalWriteEvent</code> and its own read event to be signaled. When <strong>WaitForMultipleObjects</strong> returns, the reader thread's auto-reset event has been reset to nonsignaled. This blocks the master thread from writing to the buffer until the reader thread uses the <a href="mk:@MSITStore:D:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001OCT\1033\dllproc.chm::/hh/winbase/synchro_8ut0.htm"><strong><u><font color=#800080>SetEvent</font></u></strong></a> function to set the event's state back to signaled. </p>
<pre>VOID ThreadFunction(LPVOID lpParam)
{
DWORD dwWaitResult;
HANDLE hEvents[2];
hEvents[0] = *(HANDLE*)lpParam;  // thread's read event
hEvents[1] = hGlobalWriteEvent;
dwWaitResult = WaitForMultipleObjects(
2,            // number of handles in array
hEvents,      // array of event handles
TRUE,         // wait till all are signaled
INFINITE);    // indefinite wait
switch (dwWaitResult)
{
// Both event objects were signaled.
case WAIT_OBJECT_0:
// Read from the shared buffer.
break;
// An error occurred.
default:
printf("Wait error: %d\n", GetLastError());
ExitThread(0);
}
// Set the read event to signaled.
if (! SetEvent(hEvents[0]) )
{
// Error exit.
}
}</pre>
<!-- Info Task Footer -->
<div class=itfBorder><img height=1 src="mk:@MSITStore:D:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001OCT\1033\dllproc.chm::/hh/tiny.gif" width=1></div>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/137579.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-08-17 16:20 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/08/17/137579.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Using Mutex Objects (zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/08/17/137574.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 17 Aug 2007 08:13:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/08/17/137574.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/137574.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/08/17/137574.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/137574.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/137574.html</trackback:ping><description><![CDATA[<h2><a name=_win32_using_mutex_objects></a>Using Mutex Objects</h2>
<p>You can use a mutex object to protect a shared resource from simultaneous access by multiple threads or processes. Each thread must wait for ownership of the mutex before it can execute the code that accesses the shared resource. For example, if several threads share access to a database, the threads can use a mutex object to permit only one thread at a time to write to the database. </p>
<p>In the following example, a process uses the <a href="mk:@MSITStore:D:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001OCT\1033\dllproc.chm::/hh/winbase/synchro_1a2g.htm"><strong><u><font color=#800080>CreateMutex</font></u></strong></a> function to create a named mutex object or open a handle to an existing mutex object. </p>
<pre>HANDLE hMutex;
// Create a mutex with no initial owner.
hMutex = CreateMutex(
NULL,                       // no security attributes
FALSE,                      // initially not owned
"MutexToProtectDatabase");  // name of mutex
if (hMutex == NULL)
{
// Check for error.
}</pre>
<p>When a thread of this process writes to the database, as in the next example, it first requests ownership of the mutex. If it gets ownership, the thread writes to the database and then releases its ownership. </p>
<p>The example uses structured exception-handling syntax to ensure that the thread properly releases the mutex object. The __<strong>finally</strong> block of code is executed no matter how the __<strong>try</strong> block terminates (unless the __<strong>try</strong> block includes a call to the <a href="mk:@MSITStore:D:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001OCT\1033\dllproc.chm::/hh/winbase/prothred_7h2c.htm"><strong><u><font color=#0000ff>TerminateThread</font></u></strong></a> function). This prevents the mutex object from being abandoned inadvertently.</p>
<pre>BOOL FunctionToWriteToDatabase(HANDLE hMutex)
{
DWORD dwWaitResult;
// Request ownership of mutex.
dwWaitResult = WaitForSingleObject(
hMutex,   // handle to mutex
5000L);   // five-second time-out interval
switch (dwWaitResult)
{
// The thread got mutex ownership.
case WAIT_OBJECT_0:
__try {
// Write to the database.
}
__finally {
// Release ownership of the mutex object.
if (! ReleaseMutex(hMutex)) {
// Deal with error.
}
break;
}
// Cannot get mutex ownership due to time-out.
case WAIT_TIMEOUT:
return FALSE;
// Got ownership of the abandoned mutex object.
case WAIT_ABANDONED:
return FALSE;
}
return TRUE;
}</pre>
<!-- Info Task Footer -->
<div class=itfBorder><img height=1 src="mk:@MSITStore:D:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001OCT\1033\dllproc.chm::/hh/tiny.gif" width=1></div>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/137574.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-08-17 16:13 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/08/17/137574.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC 6 调试调试子进程 zz</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/08/09/135515.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Thu, 09 Aug 2007 07:43:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/08/09/135515.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/135515.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/08/09/135515.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/135515.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/135515.html</trackback:ping><description><![CDATA[在你想要调试的子程序的代码中加入一句代码DebugBreak(); &nbsp; <br>&nbsp; 然后重新编译你的子程序的调试版本。现在调试主程序， &nbsp; <br>&nbsp; 子程序的调试版本在运行的过程中，当<nobr oncontextmenu="return false;" onmousemove=kwM(4); id=key4 onmouseover="kwE(event,4, this);" style="COLOR: #6600ff; BORDER-BOTTOM: 0px dotted; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">执行</nobr>到DebugBreak()时，将会抛出一个异常， &nbsp; <br>&nbsp; 这个异常会由操作系统捕捉到，然后弹出一个对话框，说程序遇到了问题，问你要不要发送错误<nobr oncontextmenu="return false;" onmousemove=kwM(6); id=key5 onmouseover="kwE(event,6, this);" style="COLOR: #6600ff; BORDER-BOTTOM: #6600ff 1px dotted; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">报告</nobr>，点击该对话框的调试按钮，系统又会弹出一个对话框，选择相应的调试器进行调试，然后子进程就会中断在代码DebugBreak()处，接下来就可以正常调试了。&nbsp;&nbsp; <br>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/135515.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-08-09 15:43 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/08/09/135515.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>详细解说STL string (zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/06/05/122189.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Tue, 05 Jun 2007 09:33:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/06/05/122189.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/122189.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/06/05/122189.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/122189.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/122189.html</trackback:ping><description><![CDATA[<a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString">http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString</a>&nbsp; <br><br>
<h2><a name="详细解说STL string"></a>详细解说STL string </h2>
<div class=twikiToc>
<ul>
    <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#详细解说STL string"><u><font color=#666666>详细解说STL string</font></u></a>
    <ul>
        <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#0 前言: string 的角色"><u><font color=#666666>0 前言: string 的角色</font></u></a>
        <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#1 string 使用"><u><font color=#666666>1 string 使用</font></u></a>
        <ul>
            <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#1.1 充分使用string 操作符"><u><font color=#666666>1.1 充分使用string 操作符</font></u></a>
            <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#1.2 眼花缭乱的string find 函数"><u><font color=#666666>1.2 眼花缭乱的string find 函数</font></u></a>
            <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#1.3 string insert, replace, eras"><u><font color=#666666>1.3 string insert, replace, erase</font></u></a> </li>
        </ul>
        <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#2 string 和 C风格字符串"><u><font color=#666666>2 string 和 C风格字符串</font></u></a>
        <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#3 string 和 Charactor Traits"><u><font color=#666666>3 string 和 Charactor Traits</font></u></a>
        <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#4 string 建议"><u><font color=#666666>4 string 建议</font></u></a>
        <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#5 小结"><u><font color=#666666>5 小结</font></u></a>
        <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#6 附录"><u><font color=#666666>6 附录</font></u></a>
        <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#7 参考文章"><u><font color=#666666>7 参考文章</font></u></a> </li>
    </ul>
    </li>
</ul>
</div>
<h3><a name="0 前言: string 的角色"></a>0 前言: string 的角色 </h3>
C++ 语言是个十分优秀的语言，但优秀并不表示完美。还是有许多人不愿意使用C或者C++，为什么？原因众多，其中之一就是C/C++的文本处理功能太麻烦，用起来很不方便。以前没有接触过其他语言时，每当别人这么说，我总是不屑一顾，认为他们根本就没有领会C++的精华，或者不太懂C++，现在我接触perl, php, 和Shell脚本以后，开始理解了以前为什么有人说C++文本处理不方便了。
<p>举例来说，如果文本格式是：用户名 电话号码，文件名name.txt <strong>BeautifierPlugin Error: Unable to handle "bash" syntax.</strong>
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px">Tom 23245332
Jenny 22231231
Heny 22183942
Tom 23245332
...
</pre>
</div>
现在我们需要对用户名排序，且只输出不同的姓名。
<p>那么在<a class=twikiLink href="http://www.stlchina.org/twiki/bin/view.pl/Main/ScriptShellTutorial"><u><font color=#0066cc>shell 编程</font></u></a>中，可以这样用： <strong>BeautifierPlugin Error: Unable to handle "bash" syntax.</strong>
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px">awk '{print $1}' name.txt | sort | uniq
</pre>
</div>
简单吧？
<p>如果使用C/C++ 就麻烦了，他需要做以下工作：
<ol>
    <li>先打开文件，检测文件是否打开，如果失败，则退出。
    <li>声明一个足够大得二维字符数组或者一个字符指针数组
    <li>读入一行到字符空间
    <li>然后分析一行的结构，找到空格，存入字符数组中。
    <li>关闭文件
    <li>写一个排序函数，或者使用写一个比较函数，使用qsort排序
    <li>遍历数组，比较是否有相同的，如果有，则要删除，copy...
    <li>输出信息 </li>
</ol>
你可以用C++或者C语言去实现这个流程。如果一个人的主要工作就是处理这种类似的文本(例如做apache的日志统计和分析),你说他会喜欢C/C++么？
<p>
<p>当然，有了STL，这些处理会得到很大的简化。我们可以使用 fstream来代替麻烦的fopen fread fclose, 用vector 来代替数组。最重要的是用 <a href="http://www.stlchina.org/stl_doc/basic_string.html" target=_top><u><font color=#0066cc>string</font></u></a>来代替char * 数组，使用<a class=twikiLink href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLSortAlgorithms"><u><font color=#0066cc>sort排序算法</font></u></a>来排序，用<a href="http://www.stlchina.org/stl_doc/unique.html" target=_top><u><font color=#0066cc>unique 函数</font></u></a>来去重。听起来好像很不错 <img title=smile alt=smile src="http://www.stlchina.org/twiki/pub/TWiki/SmiliesPlugin/smile.gif" border=0> 。看看下面代码(例程1）：
<div class=fragment>
<pre style="PADDING-BOTTOM: 16px"><font color=navy>#include</font> &lt;string&gt;
<font color=navy>#include</font> &lt;iostream&gt;
<font color=navy>#include</font> &lt;algorithm&gt;
<font color=navy>#include</font> &lt;vector&gt;
<font color=navy>#include</font> &lt;fstream&gt;
<font color=brown>using</font> <font color=brown>namespace</font> std;
<font color=brown>int</font> main(){
ifstream in("<font color=blue>name.txt</font>");
string strtmp;
vector&lt;string&gt; vect;
<font color=brown>while</font>(getline(in, strtmp, '\n'))
vect.push_back(strtmp.substr(0, strtmp.find(' ')));
sort(vect.begin(), vect.end());
vector&lt;string&gt;::iterator it=unique(vect.begin(), vect.end());
copy(vect.begin(), it, ostream_iterator&lt;string&gt;(cout, "<font color=blue>\n</font>"));
<font color=brown>return</font> 0;
}</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
也还不错吧，至少会比想象得要简单得多！（代码里面没有对错误进行处理，只是为了说明问题，不要效仿).
<p>当然，在这个文本格式中，不用vector而使用map会更有扩充性，例如，还可通过人名找电话号码等等，但是使用了map就不那么好用sort了。你可以用map试一试。
<p>这里string的作用不只是可以存储字符串，还可以提供字符串的比较，查找等。在sort和unique函数中就默认使用了less<string> 和equal_to<string>函数, 上面的一段代码，其实使用了string的以下功能：
<ol>
    <li>存储功能，在getline() 函数中
    <li>查找功能，在find() 函数中
    <li>子串功能，在substr() 函数中
    <li>string operator &lt; , 默认在sort() 函数中调用
    <li>string operator == , 默认在unique() 函数中调用 </li>
</ol>
<p>总之，有了string 后，C++的字符文本处理功能总算得到了一定补充，加上配合STL其他容器使用，其在文本处理上的功能已经与perl, shell, php的距离缩小很多了。 因此掌握string 会让你的工作事半功倍。
<p>
<h3><a name="1 string 使用"></a>1 string 使用 </h3>
其实，string并不是一个单独的容器，只是basic_string 模板类的一个typedef 而已，相对应的还有wstring, 你在string 头文件中你会发现下面的代码:
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px"><font color=brown>extern</font> "<font color=blue>C++</font>" {
<font color=brown>typedef</font> basic_string &lt;<font color=brown>char</font>&gt; string;
<font color=brown>typedef</font> basic_string &lt;wchar_t&gt; wstring;
} <font color=green>// extern "C++"</font></font></pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
由于只是解释string的用法，如果没有特殊的说明，本文并不区分string 和 basic_string的区别。
<p>string 其实相当于一个保存字符的序列容器，因此除了有字符串的一些常用操作以外，还有包含了所有的序列容器的操作。字符串的常用操作包括：增加、删除、修改、查找比较、链接、输入、输出等。详细函数列表参看<a class=twikiAnchorLink href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString#FuncList"><u><font color=#666666>附录</font></u></a>。不要害怕这么多函数，其实有许多是序列容器带有的，平时不一定用的上。
<p>如果你要想了解所有函数的详细用法，你需要查看<a class=twikiLink href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLBasicString"><u><font color=#0066cc>basic_string</font></u></a>，或者下载<a href="http://stl.winterxy.com/html/000035.html" target=_top rel=nofollow><u><font color=#0066cc>STL编程手册</font></u></a>。这里通过实例介绍一些常用函数。
<h4><a name="1.1 充分使用string 操作符"></a>1.1 充分使用string 操作符 </h4>
string 重载了许多操作符，包括 +, +=, &lt;, <code><font color=#7a4707>=, </font></code>, [], &lt;&lt;, &gt;&gt;等，正式这些操作符，对字符串操作非常方便。先看看下面这个例子：tt.cpp（例程2）
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px"><font color=navy>#include</font> &lt;string&gt;
<font color=navy>#include</font> &lt;iostream&gt;
<font color=brown>using</font> <font color=brown>namespace</font> std;
<font color=brown>int</font> main(){
string strinfo="<font color=blue>Please input your name:</font>";
cout &lt;&lt; strinfo ;
cin &gt;&gt; strinfo;
<font color=brown>if</font>( strinfo == "<font color=blue>winter</font>" )
cout &lt;&lt; "<font color=blue>you are winter!</font>"&lt;&lt;endl;
<font color=brown>else</font> <font color=brown>if</font>( strinfo != "<font color=blue>wende</font>" )
cout &lt;&lt; "<font color=blue>you are not wende!</font>"&lt;&lt;endl;
<font color=brown>else</font> <font color=brown>if</font>( strinfo &lt; "<font color=blue>winter</font>")
cout &lt;&lt; "<font color=blue>your name should be ahead of winter</font>"&lt;&lt;endl;
<font color=brown>else</font>
cout &lt;&lt; "<font color=blue>your name should be after of winter</font>"&lt;&lt;endl;
strinfo += "<font color=blue> , Welcome to China!</font>";
cout &lt;&lt; strinfo&lt;&lt;endl;
cout &lt;&lt;"<font color=blue>Your name is :</font>"&lt;&lt;endl;
string strtmp = "<font color=blue>How are you? </font>" + strinfo;
<font color=brown>for</font>(<font color=brown>int</font> i = 0 ; i &lt; strtmp.size(); i ++)
cout&lt;&lt;strtmp[i];
<font color=brown>return</font> 0;
} </pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
<p>下面是程序的输出 <strong>BeautifierPlugin Error: Unable to handle "bash" syntax.</strong>
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px">-bash-2.05b$ make tt
c++  -O -pipe -march=pentiumpro  tt.cpp  -o tt
-bash-2.05b$ ./tt
Please input your name:Hero
you are not wende!
Hero , Welcome to China!
How are you? Hero , Welcome to China!
</pre>
</div>
<p>有了这些操作符，在STL中仿函数都可以直接使用string作为参数，例如 less, great, equal_to 等，因此在把string作为参数传递的时候，它的使用和int 或者float等已经没有什么区别了。例如，你可以使用：
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px">map&lt;string, <font color=brown>int</font>&gt; mymap;
<font color=green>//以上默认使用了 less&lt;string&gt;</font></font></pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
有了 operator + 以后，你可以直接连加，例如：
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px">string strinfo="<font color=blue>Winter</font>";
string strlast="<font color=blue>Hello </font>" + strinfo + "<font color=blue>!</font>";
<font color=green>//你还可以这样：</font>
string strtest="<font color=blue>Hello </font>" + strinfo + "<font color=blue> Welcome</font>" + "<font color=blue> to China</font>" + "<font color=blue> !</font>";</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
看见其中的特点了吗？只要你的等式里面有一个 string 对象，你就可以一直连续"+"，但有一点需要保证的是，在开始的两项中，必须有一项是 string 对象。其原理很简单：
<ol>
    <li>系统遇到"+"号，发现有一项是string 对象。
    <li>系统把另一项转化为一个临时 string 对象。
    <li>执行 operator + 操作，返回新的临时string 对象。
    <li>如果又发现"+"号，继续第一步操作。 </li>
</ol>
由于这个等式是由左到右开始检测执行，如果开始两项都是const char* ，程序自己并没有定义两个const char* 的加法，编译的时候肯定就有问题了。
<p>有了操作符以后，assign(), append(), compare(), at()等函数，除非有一些特殊的需求时，一般是用不上。当然at()函数还有一个功能，那就是检查下标是否合法，如果是使用：
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px">string str="<font color=blue>winter</font>";
<font color=green>//下面一行有可能会引起程序中断错误</font>
str[100]='!';
<font color=green>//下面会抛出异常:throws: out_of_range</font>
cout&lt;&lt;str.at(100)&lt;&lt;endl;</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
了解了吗？如果你希望效率高，还是使用[]来访问，如果你希望稳定性好，最好使用at()来访问。
<h4><a name="1.2 眼花缭乱的string find 函数"></a>1.2 眼花缭乱的string find 函数 </h4>
由于查找是使用最为频繁的功能之一，string 提供了非常丰富的查找函数。其列表如下：
<table class=twikiTable cellSpacing=1 cellPadding=1 border=0>
    <tbody>
        <tr>
            <td class=twikiFirstCol align=middle bgColor=#eaeaea>函数名 </td>
            <td align=middle bgColor=#eaeaea>描述 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>find </td>
            <td bgColor=#ffffff>查找 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>rfind </td>
            <td bgColor=#eaeaea>反向查找 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>find_first_of </td>
            <td bgColor=#ffffff>查找包含子串中的任何字符，返回第一个位置 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>find_first_not_of </td>
            <td bgColor=#eaeaea>查找不包含子串中的任何字符，返回第一个位置 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>find_last_of </td>
            <td bgColor=#ffffff>查找包含子串中的任何字符，返回最后一个位置 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>find_last_not_of </td>
            <td bgColor=#eaeaea>查找不包含子串中的任何字符，返回最后一个位置 </td>
        </tr>
    </tbody>
</table>
以上函数都是被重载了4次，以下是以find_first_of 函数为例说明他们的参数，其他函数和其参数一样，也就是说总共有24个函数 <img title=smile alt=smile src="http://www.stlchina.org/twiki/pub/TWiki/SmiliesPlugin/smile.gif" border=0> ：
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px">size_type find_first_of(<font color=brown>const</font> basic_string&amp; s, size_type pos = 0)
size_type find_first_of(<font color=brown>const</font> charT* s, size_type pos, size_type n)
size_type find_first_of(<font color=brown>const</font> charT* s, size_type pos = 0)
size_type find_first_of(charT c, size_type pos = 0)</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
所有的查找函数都返回一个size_type类型，这个返回值一般都是所找到字符串的位置，如果没有找到，则返回string::npos。有一点需要特别注意，所有和string::npos的比较一定要用string::size_type来使用，不要直接使用int 或者unsigned int等类型。其实string::npos表示的是-1, 看看头文件：
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px"><font color=brown>template</font> &lt;<font color=brown>class</font> _CharT, <font color=brown>class</font> _Traits, <font color=brown>class</font> _Alloc&gt;
<font color=brown>const</font> basic_string&lt;_CharT,_Traits,_Alloc&gt;::size_type
basic_string&lt;_CharT,_Traits,_Alloc&gt;::npos
= basic_string&lt;_CharT,_Traits,_Alloc&gt;::size_type) -1;</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
<p>find 和 rfind 都还比较容易理解，一个是正向匹配，一个是逆向匹配，后面的参数pos都是用来指定起始查找位置。对于find_first_of 和find_last_of 就不是那么好理解。
<p>find_first_of 是给定一个要查找的字符集，找到这个字符集中任何一个字符所在字符串中第一个位置。或许看一个例子更容易明白。
<p>有这样一个需求：过滤一行开头和结尾的所有非英文字符。看看用string 如何实现：
<div class=fragment>
<pre style="PADDING-BOTTOM: 16px"><font color=navy>#include</font> &lt;string&gt;
<font color=navy>#include</font> &lt;iostream&gt;
<font color=brown>using</font> <font color=brown>namespace</font> std;
<font color=brown>int</font> main(){
string strinfo="<font color=blue>   //*---Hello Word!......------</font>";
string strset="<font color=blue>ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz</font>";
<font color=brown>int</font> first = strinfo.find_first_of(strset);
<font color=brown>if</font>(first == string::npos) {
cout&lt;&lt;"<font color=blue>not find any characters</font>"&lt;&lt;endl;
<font color=brown>return</font> -1;
}
<font color=brown>int</font> last = strinfo.find_last_of(strset);
<font color=brown>if</font>(last == string::npos) {
cout&lt;&lt;"<font color=blue>not find any characters</font>"&lt;&lt;endl;
<font color=brown>return</font> -1;
}
cout &lt;&lt; strinfo.substr(first, last - first + 1)&lt;&lt;endl;
<font color=brown>return</font> 0;
}</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
这里把所有的英文字母大小写作为了需要查找的字符集，先查找第一个英文字母的位置，然后查找最后一个英文字母的位置，然后用substr 来的到中间的一部分，用于输出结果。下面就是其结果：
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px">Hello Word</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
前面的符号和后面的符号都没有了。像这种用法可以用来查找分隔符，从而把一个连续的字符串分割成为几部分，达到 shell 命令中的 awk 的用法。特别是当分隔符有多个的时候，可以一次指定。例如有这样的需求：
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px">张三|3456123, 湖南
李四,4564234| 湖北
王小二, 4433253|北京
...</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
我们需要以 "|" ","为分隔符，同时又要过滤空格，把每行分成相应的字段。可以作为你的一个家庭作业来试试，要求代码简洁。
<h4><a name="1.3 string insert, replace, eras"></a>1.3 string insert, replace, erase </h4>
了解了string 的操作符，查找函数和substr，其实就已经了解了string的80%的操作了。insert函数, replace函数和erase函数在使用起来相对简单。下面以一个例子来说明其应用。
<p>string只是提供了按照位置和区间的replace函数，而不能用一个string字串来替换指定string中的另一个字串。这里写一个函数来实现这个功能：
<div class=fragment>
<pre style="PADDING-BOTTOM: 16px"><font color=brown>void</font> string_replace(string &amp; strBig, <font color=brown>const</font> string &amp; strsrc, <font color=brown>const</font> string &amp;strdst) {
string::size_type pos=0;
string::size_type srclen=strsrc.size();
string::size_type dstlen=strdst.size();
<font color=brown>while</font>( (pos=strBig.find(strsrc, pos)) != string::npos){
strBig.replace(pos, srclen, strdst);
pos += dstlen;
}
}</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
看看如何调用：
<div class=fragment>
<pre style="PADDING-BOTTOM: 16px"><font color=navy>#include</font> &lt;string&gt;
<font color=navy>#include</font> &lt;iostream&gt;
<font color=brown>using</font> <font color=brown>namespace</font> std;
<font color=brown>int</font> main() {
string strinfo="<font color=blue>This is Winter, Winter is a programmer. Do you know Winter?</font>";
cout&lt;&lt;"<font color=blue>Orign string is :\n</font>"&lt;&lt;strinfo&lt;&lt;endl;
string_replace(strinfo, "<font color=blue>Winter</font>", "<font color=blue>wende</font>");
cout&lt;&lt;"<font color=blue>After replace Winter with wende, the string is :\n</font>"&lt;&lt;strinfo&lt;&lt;endl;
<font color=brown>return</font> 0;
}</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
其输出结果：
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px">Orign string is :
This is Winter, Winter is a programmer. Do you know Winter?
After replace Winter with wende, the string is :
This is wende, wende is a programmer. Do you know wende?</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
如果不用replace函数，则可以使用erase和insert来替换，也能实现string_replace函数的功能：
<div class=fragment>
<pre style="PADDING-BOTTOM: 16px"><font color=brown>void</font> string_replace(string &amp; strBig, <font color=brown>const</font> string &amp; strsrc, <font color=brown>const</font> string &amp;strdst) {
string::size_type pos=0;
string::size_type srclen=strsrc.size();
string::size_type dstlen=strdst.size();
<font color=brown>while</font>( (pos=strBig.find(strsrc, pos)) != string::npos){
strBig.erase(pos, srclen);
strBig.insert(pos, strdst);
pos += dstlen;
}
}</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
当然，这种方法没有使用replace来得直接。
<h3><a name="2 string 和 C风格字符串"></a>2 string 和 C风格字符串 </h3>
现在看了这么多例子，发现const char* 可以和string 直接转换，例如我们在上面的例子中，使用
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px">string_replace(strinfo, "<font color=blue>Winter</font>", "<font color=blue>wende</font>");</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
来代用
<div class=fragment>
<pre style="PADDING-BOTTOM: 16px"><font color=brown>void</font> string_replace(string &amp; strBig, <font color=brown>const</font> string &amp; strsrc, <font color=brown>const</font> string &amp;strdst) </pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
在C语言中只有char* 和 const char*，为了使用起来方便，string提供了三个函数满足其要求：
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px"><font color=brown>const</font> charT* c_str() <font color=brown>const</font>
<font color=brown>const</font> charT* data() <font color=brown>const</font>
size_type copy(charT* buf, size_type n, size_type pos = 0) <font color=brown>const</font> </pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
其中：
<ol>
    <li>c_str 直接返回一个以\0结尾的字符串。
    <li>data 直接以数组方式返回string的内容，其大小为size()的返回值，结尾并没有\0字符。
    <li>copy 把string的内容拷贝到buf空间中。 </li>
</ol>
你或许会问，c_str()的功能包含data()，那还需要data()函数干什么？看看源码：
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px"><font color=brown>const</font> charT* c_str () <font color=brown>const</font>
{ <font color=brown>if</font> (length () == 0) <font color=brown>return</font> "<font color=blue></font>"; terminate (); <font color=brown>return</font> data (); }</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
原来c_str()的流程是：先调用terminate()，然后在返回data()。因此如果你对效率要求比较高，而且你的处理又不一定需要以\0的方式结束，你最好选择data()。但是对于一般的C函数中，需要以const char*为输入参数，你就要使用c_str()函数。
<p>对于c_str() data()函数，返回的数组都是由string本身拥有，千万不可修改其内容。其原因是许多string实现的时候采用了引用机制，也就是说，有可能几个string使用同一个字符存储空间。而且你不能使用sizeof(string)来查看其大小。详细的解释和实现查看<a href="http://stl.winterxy.com/html/000030.html" target=_top rel=nofollow><u><font color=#0066cc>Effective STL</font></u></a>的条款15：<a href="http://stl.winterxy.com/html/item_15.html" target=_top rel=nofollow><u><font color=#0066cc>小心string实现的多样性</font></u></a>。
<p>另外在你的程序中，只在需要时才使用c_str()或者data()得到字符串，每调用一次，下次再使用就会失效，如：
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px">string strinfo("<font color=blue>this is Winter</font>");
...
<font color=green>//最好的方式是:</font>
foo(strinfo.c_str());
<font color=green>//也可以这么用:</font>
<font color=brown>const</font> <font color=brown>char</font>* pstr=strinfo.c_str();
foo(pstr);
<font color=green>//不要再使用了pstr了, 下面的操作已经使pstr无效了。</font>
strinfo += "<font color=blue> Hello!</font>";
foo(pstr);<font color=green>//错误！</font></font></pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
会遇到什么错误？当你幸运的时候pstr可能只是指向"this is Winter Hello!"的字符串，如果不幸运，就会导致程序出现其他问题，总会有一些不可遇见的错误。总之不会是你预期的那个结果。
<p>
<h3><a name="3 string 和 Charactor Traits"></a>3 string 和 Charactor Traits </h3>
了解了string的用法，该详细看看string的真相了。前面提到string 只是basic_string的一个typedef。看看basic_string 的参数：
<div class=fragment>
<pre style="PADDING-BOTTOM: 0px"><font color=brown>template</font> &lt;<font color=brown>class</font> charT, <font color=brown>class</font> traits = char_traits&lt;charT&gt;,
<font color=brown>class</font> Allocator = allocator&lt;charT&gt; &gt;
<font color=brown>class</font> basic_string
{
<font color=green>//...</font>
}</pre>
<pre style="PADDING-BOTTOM: 0px"></pre>
</div>
char_traits不仅是在basic_string 中有用，在basic_istream 和 basic_ostream中也需要用到。
<p>就像Steve Donovan在<a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLOverdoTemplates" target=_top><u><font color=#666666>过度使用C++模板</font></u></a>中提到的，这些确实有些过头了，要不是系统自己定义了相关的一些属性，而且用了个typedef，否则还真不知道如何使用。
<p>但复杂总有复杂道理。有了char_traits，你可以定义自己的字符串类型。当然，有了char_traits &lt; char &gt; 和char_traits &lt; wchar_t &gt; 你的需求使用已经足够了，为了更好的理解string ，咱们来看看char_traits都有哪些要求。
<p>如果你希望使用你自己定义的字符，你必须定义包含下列成员的结构：
<table class=twikiTable cellSpacing=1 cellPadding=1 border=0>
    <tbody>
        <tr>
            <th class=twikiFirstCol bgColor=#dadada><a title="Sort by this column" href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString?sortcol=0;table=2;up=0#sorted_table" rel=nofollow><font color=#0066cc>表达式</font></a> </th>
            <th align=middle bgColor=#dadada><a title="Sort by this column" href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailString?sortcol=1;table=2;up=0#sorted_table" rel=nofollow><font color=#0066cc>描述</font></a> </th>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>char_type </td>
            <td bgColor=#ffffff>字符类型 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>int_type </td>
            <td bgColor=#eaeaea>int 类型 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>pos_type </td>
            <td bgColor=#ffffff>位置类型 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>off_type </td>
            <td bgColor=#eaeaea>表示位置之间距离的类型 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>state_type </td>
            <td bgColor=#ffffff>表示状态的类型 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>assign(c1,c2) </td>
            <td bgColor=#eaeaea>把字符c2赋值给c1 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>eq(c1,c2) </td>
            <td bgColor=#ffffff>判断c1,c2 是否相等 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>lt(c1,c2) </td>
            <td bgColor=#eaeaea>判断c1是否小于c2 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>length(str) </td>
            <td bgColor=#ffffff>判断str的长度 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>compare(s1,s2,n) </td>
            <td bgColor=#eaeaea>比较s1和s2的前n个字符 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>copy(s1,s2, n) </td>
            <td bgColor=#ffffff>把s2的前n个字符拷贝到s1中 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>move(s1,s2, n) </td>
            <td bgColor=#eaeaea>把s2中的前n个字符移动到s1中 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>assign(s,n,c) </td>
            <td bgColor=#ffffff>把s中的前n个字符赋值为c </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>find(s,n,c) </td>
            <td bgColor=#eaeaea>在s的前n个字符内查找c </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>eof() </td>
            <td bgColor=#ffffff>返回end-of-file </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>to_int_type(c) </td>
            <td bgColor=#eaeaea>将c转换成int_type </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>to_char_type(i) </td>
            <td bgColor=#ffffff>将i转换成char_type </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>not_eof(i) </td>
            <td bgColor=#eaeaea>判断i是否为EOF </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>eq_int_type(i1,i2) </td>
            <td bgColor=#ffffff>判断i1和i2是否相等 </td>
        </tr>
    </tbody>
</table>
想看看实际的例子，你可以看看sgi STL的<a href="http://www.stlchina.org/stl_doc/char_traits.h" target=_top><u><font color=#0066cc>char_traits结构源码</font></u></a>.
<p>现在默认的string版本中，并不支持忽略大小写的比较函数和查找函数，如果你想练练手，你可以试试改写一个char_traits , 然后生成一个case_string类, 也可以在string 上做继承，然后派生一个新的类，例如：ext_string，提供一些常用的功能，例如：
<ol>
    <li>定义分隔符。给定分隔符，把string分为几个字段。
    <li>提供替换功能。例如，用winter, 替换字符串中的wende
    <li>大小写处理。例如，忽略大小写比较，转换等
    <li>整形转换。例如把"123"字符串转换为123数字。 </li>
</ol>
这些都是常用的功能，如果你有兴趣可以试试。其实有人已经实现了，看看<a href="http://www.gotroot.ca/ext_string/" target=_top rel=nofollow><u><font color=#0066cc>Extended STL string</font></u></a>。如果你想偷懒，下载一个头文件就可以用，有了它确实方便了很多。要是有人能提供一个支持正则表达式的string，我会非常乐意用。
<p>
<h3><a name="4 string 建议"></a>4 string 建议 </h3>
使用string 的方便性就不用再说了，这里要重点强调的是string的安全性。
<ol>
    <li>string并不是万能的，如果你在一个大工程中需要频繁处理字符串，而且有可能是多线程，那么你一定要慎重(当然，在多线程下你使用任何STL容器都要慎重)。
    <li>string的实现和效率并不一定是你想象的那样，如果你对大量的字符串操作，而且特别关心其效率，那么你有两个选择，首先，你可以看看你使用的STL版本中string实现的源码；另一选择是你自己写一个只提供你需要的功能的类。
    <li>string的c_str()函数是用来得到C语言风格的字符串，其返回的指针不能修改其空间。而且在下一次使用时重新调用获得新的指针。
    <li>string的data()函数返回的字符串指针不会以'\0'结束，千万不可忽视。
    <li>尽量去使用操作符，这样可以让程序更加易懂（特别是那些脚本程序员也可以看懂） </li>
</ol>
<h3><a name="5 小结"></a>5 小结 </h3>
难怪有人说：<br><strong>string 使用方便功能强，我们一直用它！</strong>
<p>
<h3><a name="6 附录"></a>6 附录 </h3>
<a name=FuncList></a>string 函数列表
<table class=twikiTable cellSpacing=1 cellPadding=1 border=0>
    <tbody>
        <tr>
            <td class=twikiFirstCol align=middle bgColor=#eaeaea>函数名 </td>
            <td align=middle bgColor=#eaeaea>描述 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>begin </td>
            <td bgColor=#ffffff>得到指向字符串开头的Iterator </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>end </td>
            <td bgColor=#eaeaea>得到指向字符串结尾的Iterator </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>rbegin </td>
            <td bgColor=#ffffff>得到指向反向字符串开头的Iterator </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>rend </td>
            <td bgColor=#eaeaea>得到指向反向字符串结尾的Iterator </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>size </td>
            <td bgColor=#ffffff>得到字符串的大小 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>length </td>
            <td bgColor=#eaeaea>和size函数功能相同 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>max_size </td>
            <td bgColor=#ffffff>字符串可能的最大大小 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>capacity </td>
            <td bgColor=#eaeaea>在不重新分配内存的情况下，字符串可能的大小 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>empty </td>
            <td bgColor=#ffffff>判断是否为空 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>operator[] </td>
            <td bgColor=#eaeaea>取第几个元素，相当于数组 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>c_str </td>
            <td bgColor=#ffffff>取得C风格的const char* 字符串 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>data </td>
            <td bgColor=#eaeaea>取得字符串内容地址 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>operator= </td>
            <td bgColor=#ffffff>赋值操作符 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>reserve </td>
            <td bgColor=#eaeaea>预留空间 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>swap </td>
            <td bgColor=#ffffff>交换函数 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>insert </td>
            <td bgColor=#eaeaea>插入字符 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>append </td>
            <td bgColor=#ffffff>追加字符 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>push_back </td>
            <td bgColor=#eaeaea>追加字符 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>operator+= </td>
            <td bgColor=#ffffff>+= 操作符 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>erase </td>
            <td bgColor=#eaeaea>删除字符串 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>clear </td>
            <td bgColor=#ffffff>清空字符容器中所有内容 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>resize </td>
            <td bgColor=#eaeaea>重新分配空间 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>assign </td>
            <td bgColor=#ffffff>和赋值操作符一样 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>replace </td>
            <td bgColor=#eaeaea>替代 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>copy </td>
            <td bgColor=#ffffff>字符串到空间 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>find </td>
            <td bgColor=#eaeaea>查找 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>rfind </td>
            <td bgColor=#ffffff>反向查找 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>find_first_of </td>
            <td bgColor=#eaeaea>查找包含子串中的任何字符，返回第一个位置 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>find_first_not_of </td>
            <td bgColor=#ffffff>查找不包含子串中的任何字符，返回第一个位置 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>find_last_of </td>
            <td bgColor=#eaeaea>查找包含子串中的任何字符，返回最后一个位置 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>find_last_not_of </td>
            <td bgColor=#ffffff>查找不包含子串中的任何字符，返回最后一个位置 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>substr </td>
            <td bgColor=#eaeaea>得到字串 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>compare </td>
            <td bgColor=#ffffff>比较字符串 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>operator+ </td>
            <td bgColor=#eaeaea>字符串链接 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>operator== </td>
            <td bgColor=#ffffff>判断是否相等 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>operator!= </td>
            <td bgColor=#eaeaea>判断是否不等于 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>operator&lt; </td>
            <td bgColor=#ffffff>判断是否小于 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>operator&gt;&gt; </td>
            <td bgColor=#eaeaea>从输入流中读入字符串 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#ffffff>operator&lt;&lt; </td>
            <td bgColor=#ffffff>字符串写入输出流 </td>
        </tr>
        <tr>
            <td class=twikiFirstCol bgColor=#eaeaea>getline </td>
            <td bgColor=#eaeaea>从输入流中读入一行 </td>
        </tr>
    </tbody>
</table>
<p>
<h3><a name="7 参考文章"></a>7 参考文章 </h3>
<ol>
    <li><a href="http://www.stlchina.org/stl_doc/char_traits.h" target=_top><u><font color=#0066cc>SGI STL: char_traits 源码</font></u></a>
    <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLBasicString" target=_top><font color=#0066cc><u>STL 编程手册: basic_string </u></font></a>
    <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLSortAlgorithms" target=_top><u><font color=#0066cc>详细解说 STL 排序(Sort)</font></u></a>
    <li><a href="http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailHashMap" target=_top><u><font color=#0066cc>详细解说 STL hash_map系列</font></u></a>
    <li><a href="http://stl.winterxy.com/html/000016.html" target=_top rel=nofollow><u><font color=#0066cc>Effective STL 中文版</font></u></a> </li>
</ol>
<!--
<ul>
    <li> Set MYTITLE = 详细解说STL string
    </li>
</ul>
-->
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/122189.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-06-05 17:33 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/06/05/122189.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>便利的开发文档工具-doxygen</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/06/01/121339.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 01 Jun 2007 05:17:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/06/01/121339.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/121339.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/06/01/121339.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/121339.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/121339.html</trackback:ping><description><![CDATA[<p><a href="http://www.moon-soft.com/doc/39077.htm">http://www.moon-soft.com/doc/39077.htm</a><br><br><br>便利的开发文档工具-doxygen<br>mounton @ {www.ihere.org} ( <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#109;&#111;&#117;&#110;&#116;&#48;&#110;&#64;&#121;&#97;&#104;&#111;&#111;&#46;&#99;&#111;&#109;"><u><font color=#0000ff>mount0n@yahoo.com</font></u></a>)<br>2003年8月</p>
<p>0. 序言<br>为代码写注释一直是大多数程序员有些困扰的事情。当前程序员都能接受为了程序的可维护性、可读性编码的同时写注释的说法，但对哪些地方应该写注释，注释如何写，写多少等这些问题，很多程序员仍然没有答案。更头痛的是写文档，以及维护文档的问题，开发人员通常可以忍受编写或者改动代码时编写或者修改对应的注释，但之后需要修正相应的文档却比较困难。如果能从注释直接转化成文档，对开发人员无疑是一种福音。而doxygen就能把遵守某种格式的注释自动转化为对应的文档。</p>
<p>Doxygen是基于GPL的开源项目，是一个非常优秀的文档系统，当前支持在大多数unix（包括linux），windows家族，Mac系统上运行，完全支持C++, C, Java, IDL（Corba和Microsoft 家族）语言，部分支持PHP和C#语言，输出格式包括HTML、latex、RTF、ps、PDF、压缩的HTML和unix manpage。有很多开源项目（包括前两篇文章介绍的log4cpp和CppUnit）都使用了doxygen文档系统。而国内的开发人员却使用的不多，这里从开发人员使用的角度介绍这个工具，使开发人员用最少的代价尽快掌握这种技术，并结合这个工具探讨如何撰写注释的问题。以下以linux下的C++语言为例进行介绍，以下讨论基于doxygen1.3.3。</p>
<p>1. doxygen使用步骤<br>由于只是工具的使用，这里不介绍它的原理，直接从使用步骤开始。Doxygen的使用步骤非常简单。主要可以分为：<br>&nbsp;1）第一次使用需要安装doxygen的程序<br>&nbsp;2）生成doxygen配置文件<br>&nbsp;3）编码时，按照某种格式编写注释<br>&nbsp;4）生成对应文档<br>doxygen的安装非常简单， linux下可以直接下载安装包运行即可，下载源代码编译安装也是比较通用的编译安装命令。请参考其安装文档完成安装。</p>
<p>Doxygen在生成文档时可以定义项目属性以及文档生成过程中的很多选项，使用下面命令能够产生一个缺省的配置文件：<br>doxygen -g&nbsp; [配置文件名]<br>可以根据项目的具体需求修改配置文件中对应的项，具体的修改过程在下面介绍。修改过的配置文件可以作为以后项目的模板。</p>
<p>让doxygen自动产生文档，平常的注释风格可不行，需要遵循doxygen自己的格式。具体如何写doxygen认识的注释在第3节详细介绍。</p>
<p>OK，代码编完了，注释也按照格式写好了，最后的文档是如何的哪？非常简单，运行下面的命令，相应的文档就会产生在指定的目录中。<br>&nbsp;&nbsp;doxygen [配置文件名]</p>
<p>需要注意的是doxygen并不处理所有的注释，doxygen重点关注与程序结构有关的注释，比如：文件、类、结构、函数、变量、宏等注释，而忽略函数内变量、代码等的注释。</p>
<p>2. doxygen配置文件<br>doxygen配置文件的格式是也是通常的unix下配置文件的格式：注释'#'开始；tag = value [,value2&#8230;]；对于多值的情况可以使用 tag += value [,value2&#8230;]。</p>
<p>对doxygen的配置文件的修改分为两类：一种就是输出选项，控制如何解释源代码、如何输出；一种就是项目相关的信息，比如项目名称、源代码目录、输出文档目录等。对于第一种设置好后，通常所有项目可以共用一份配置，而后一种是每个项目必须设置的。下面选择重要的，有可能需要修改的选项进行解释说明，其他选项在配置文件都有详细解释。</p>
<p>TAG&nbsp;缺省值&nbsp;含义<br>PROJECT_NAME&nbsp;&nbsp;项目名称<br>PROJECT_NUMBER&nbsp;&nbsp;可以理解为版本信息<br>OUTPUT_DIRECTORY&nbsp;&nbsp;输出文件到的目录，相对目录（doxygen运行目录）或者绝对目录<br>INPUT&nbsp;&nbsp;代码文件或者代码所在目录，使用空格分割<br>FILE_PATTERNS&nbsp;*.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp *.h++ *.idl *.odl&nbsp;指定INPUT的目录中特定文件，如：*.cpp *.c *.h <br>RECURSIVE&nbsp;NO&nbsp;是否递归INPUT中目录的子目录<br>EXCLUDE&nbsp;&nbsp;在INPUT目录中需要忽略的子目录<br>EXCLUDE_PATTERNS&nbsp;&nbsp;明确指定的在INPUT目录中需要忽略的文件，如：FromOut*.cpp<br>&nbsp;&nbsp;<br>OUTPUT_LANGUAGE&nbsp;English&nbsp;生成文档的语言，当前支持2、30种语言，国内用户可以设置为Chinese<br>USE_WINDOWS_ENCODING&nbsp;YES（win版本）<br>NO（unix版本）&nbsp;编码格式，默认即可。<br>EXTRACT_ALL&nbsp;NO&nbsp;为NO，只解释有doxygen格式注释的代码；为YES，解析所有代码，即使没有注释。类的私有成员和所有的静态项由EXTRACT_PRIVATE和 EXTRACT_STATIC控制<br>EXTRACT_PRIVATE&nbsp;NO&nbsp;是否解析类的私有成员<br>EXTRACT_STATIC&nbsp;NO&nbsp;是否解析静态项<br>EXTRACT_LOCAL_CLASSES&nbsp;YES&nbsp;是否解析源文件（cpp文件）中定义的类<br>SOURCE_BROWSER&nbsp;NO&nbsp;如果为YES，源代码文件会被包含在文档中<br>INLINE_SOURCES&nbsp;NO&nbsp;如果为YES，函数和类的实现代码被包含在文档中<br>ALPHABETICAL_INDEX&nbsp;NO&nbsp;生成一个字母序的列表，有很多类、结构等项时建议设为YES<br>GENERATE_HTML&nbsp;YES&nbsp;是否生成HTML格式文档<br>GENERATE_HTMLHELP&nbsp;NO&nbsp;是否生成压缩HTML格式文档（.chm）<br>GENERATE_LATEX&nbsp;YES&nbsp;是否乘车latex格式的文档<br>GENERATE_RTF&nbsp;NO&nbsp;是否生成RTF格式的文档<br>GENERATE_MAN&nbsp;NO&nbsp;是否生成man格式文档<br>GENERATE_XML&nbsp;NO&nbsp;是否生成XML格式文档<br>&nbsp;&nbsp;</p>
<p>3. doxygen注释<br>3.1 注释风格<br>下面是工作量最大部分，安装doxygen格式写注释。通常代码可以附上一个注释块来对代码进行解释，一个注释块由一行或者多行组成。通常一个注释块包括一个简要说明（brief）和一个详细说明（detailed），这两部分都是可选的。可以有多种方式标识出doxygen可识别的注释块。<br>1）JavaDoc类型的多行注释。<br>/**<br>&nbsp;*&nbsp; &#8230;.text&#8230;.<br>&nbsp;*/<br>2）QT样式的多行注释。<br>/*!<br>&#8230;.text&#8230;.<br>&nbsp;*/<br>3） /// &#8230;text&#8230;.<br>4） //! &#8230;text&#8230;.<br>简要说明有多种方式标识，这里推荐使用@brief命令强制说明，例如：<br>/**<br>&nbsp;* @brief [some brief description ]<br>&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ brief description more. ]<br>&nbsp;* <br>&nbsp;* [some more detailed description&#8230;]<br>&nbsp;*/<br>以上这些注释格式用来对紧跟其后的代码进行注释。doxygen也允许把注释放到代码后面，具体格式是放一个'&lt;'到注释开始部分。例如：<br>int var1 ; /**&lt; &#8230;.text&#8230;. */<br>int var2; ///&lt; &#8230;.text&#8230;.</p>
<p>注释和代码完全分离，放在其他地方也是允许的，但需要使用特殊的命令加上名称或者声明进行标识，比如：class、struct、union、enum、fn、var、def、file、namespace、package、interface（这些也就是doxygen关注的注释类型）。这里不推荐使用，建议注释尽量放在代码前后。具体使用方式参见doxygen手册。</p>
<p>3.2 doxygen常用注释格式<br>通常的选择上面的一、两种注释风格，遇到头文件中各种类型定义，关键变量、宏的定义，在其前或者后使用 @brief 定义其简要说明，空一行后继续写其详细的注释即可。</p>
<p>对函数的注释，是比较常常需要注释的部分。除了定义其简要说明以及详细注释，还可以使用param命令对其各个参数进行注释，使用return命令对返回值进行注释。常见的格式如下：<br>/**<br>&nbsp;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#42;&#64;&#98;&#114;&#105;&#101;&#102;"><u><font color=#0000ff>*@brief</font></u></a> func's brief comment.<br>&nbsp;*<br>&nbsp;* Some detailed comment.<br>&nbsp;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#42;&#64;&#112;&#97;&#114;&#97;&#109;"><u><font color=#0000ff>*@param</font></u></a> a [param a 's comment.]<br>&nbsp;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#42;&#64;&#112;&#97;&#114;&#97;&#109;"><u><font color=#0000ff>*@param</font></u></a> b [param b 's comment.]<br>&nbsp;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#42;&#64;&#101;&#120;&#99;&#101;&#112;&#116;&#105;&#111;&#110;"><u><font color=#0000ff>*@exception</font></u></a> std::out_of_range [exception's comment.]<br>&nbsp;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#42;&#64;&#114;&#101;&#116;&#117;&#114;&#110;"><u><font color=#0000ff>*@return</font></u></a> [return's comment.]<br>&nbsp;*/<br>int func1(int a, int b);</p>
<p>进行设计时，通常有模块的概念，一个模块可能有多个类或者函数组成，完成某个特定功能的代码的集合。如何对这个概念进行注释？doxygen提供了group的概念，生成的模块的注释会单独放在一个模块的页面中。使用下面的格式定义一个group。<br>/** [group_name] [brief group description ]<br>&nbsp;* detailed group description ]<br>&nbsp;* @{<br>*/<br>code<br>/** @} */<br>group中的代码可以有自己的注释。单纯定义一个模块，去除{ 和}命令即可。任何其他代码项（比如类、函数、甚至文件）如果要加入到某个模块，可以在其doxygen注释中使用ingroup命令即可。Group之间使用ingroup命令，可以组成树状关系。<br>/** @file util.cpp <br>* @ingroup [group_name]<br>&nbsp;* @brief file's brief info.<br>&nbsp;*/<br>把多个代码项一起添加到某个模块中可以使用addtogroup命令，格式和defgroup相似。</p>
<p>对于某几个功能类似的代码项（比如类、函数、变量）等，如果希望一起添加注释，而又不想提升到模块的概念，可以通过下面的方式：<br>//@{<br>/** Comments for all below code. */<br>code&#8230;<br>//@}<br>对这种组进行命名可以使用name命令。此时中间代码可以有自己的注释。如：<br>/** @name group_name<br>&nbsp;* description for group.<br>&nbsp;*/<br>//@{<br>code&#8230;<br>//@}</p>
<p>3.3 doxygen常用注释命令<br>doxygen通过注释命令识别注释中需要特殊处理的注释，比如函数的参数、返回值进行突出显示。上面也提到了一些注释命令（如：brief、param、return、以及group相关的命令），下面对其他一些常用的注释命令进行解释说明。<br>@exception &lt;exception-object&gt; {exception description}&nbsp;对一个异常对象进行注释。<br>@warning {warning message }&nbsp;一些需要注意的事情<br>@todo { things to be done } &nbsp;对将要做的事情进行注释<br>@see {comment with reference to other items } 一段包含其他部分引用的注释，中间包含对其他代码项的名称，自动产生对其的引用链接。<br>@relates &lt;name&gt; 通常用做把非成员函数的注释文档包含在类的说明文档中。<br>@since {text} 通常用来说明从什么版本、时间写此部分代码。<br>@deprecated<br>@pre { description of the precondition } 用来说明代码项的前提条件。<br>@post { description of the postcondition } 用来说明代码项之后的使用条件。<br>@code 在注释中开始说明一段代码，直到@endcode命令。<br>@endcode 注释中代码段的结束。</p>
<p>到此为止，常用的doxygen的注释格式讨论完毕，我们能够按照一定的格式撰写doxygen认识的注释，并能够使用doxygen方便快捷的生成对应的文档，不过注释中应该写些什么，如何撰写有效的注释可能是困扰开发人员的一个更深层次的问题。</p>
<p>4. 注释的书写<br>注释应该怎么写，写多还是写少。过多的注释甚至会干扰对代码的阅读。写注释的一个总的原则就是注释应该尽量用来表明作者的意图，至少也应该是对一部分代码的总结，而不应该是对代码的重复或者解释。对代码的重复或者解释的代码，看代码可能更容易理解。反映作者意图的注释解释代码的目的，从解决问题的层次上进行注释，而代码总结性注释则是从问题的解答的层次上进行注释。</p>
<p>推荐的写注释的过程是首先使用注释勾勒出代码的主要框架，然后根据注释撰写相应的代码。对各种主要的数据结构、输出的函数、多个函数公用的变量进行详细地注释。对代码中控制结构，单一目的的语句集进行注释。下面是一些写注释时需要注意的要点：<br>&nbsp;&nbsp;避免对单独语句进行注释；<br>&nbsp;&nbsp;通过注释解释为什么这么做、或者要做什么，使代码的读者可以只阅读注释理解代码；<br>&nbsp;&nbsp;对读者可能会有疑问的地方进行注释；<br>&nbsp;&nbsp;对数据定义进行注释，而不是对其使用过程进行注释；<br>&nbsp;&nbsp;对于难于理解的代码，进行改写，而不要试图通过注释加以说明；<br>&nbsp;&nbsp;对关键的控制结构进行注释；<br>&nbsp;&nbsp;对数据和函数的边界、使用前提等进行注释；</p>
<p>5. 参考资料<br>&nbsp;1. doxygen homepage<br>&nbsp;<a href="http://www.stack.nl/~dimitri/doxygen/"><u><font color=#0000ff>http://www.stack.nl/~dimitri/doxygen/</font></u></a></p>
<p>&nbsp;2. doxygen manual <br>&nbsp;<a href="http://www.stack.nl/~dimitri/doxygen/manual.html"><u><font color=#0000ff>http://www.stack.nl/~dimitri/doxygen/manual.html</font></u></a></p>
<p>&nbsp;3. Code Complete: A Practical Handbook of Software Construction. Redmond, Wa.: Microsoft Press, 880 pages, 1993. ISBN: 1-55615-484-4. <br>&nbsp;<br>&nbsp;4. 简介doxygen<br>&nbsp;<a href="http://www.stack.nl/~dimitri/doxygen/doxygen_intro_cn.html"><u><font color=#800080>http://www.stack.nl/~dimitri/doxygen/doxygen_intro_cn.html</font></u></a><br>&nbsp;<br>&nbsp;5. 10 Minutes to document your code<br>&nbsp;<a href="http://www.codeproject.com/tips/doxysetup.asp"><u><font color=#0000ff>http://www.codeproject.com/tips/doxysetup.asp</font></u></a></p>
<p>&nbsp;6. 使用doxygen<br>&nbsp;<a href="http://www.csdn.net/Develop/article/16%5C16383.shtm"><u><font color=#0000ff>http://www.csdn.net/Develop/article/16%5C16383.shtm</font></u></a></p>
<p>&nbsp;<br>6. 关于作者<br>mounton @ {www.ihere.org} 当前关注于网络安全产品的开发、研究；软件开发过程等方面。您可以通过<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#109;&#111;&#117;&#110;&#116;&#48;&#110;&#64;&#121;&#97;&#104;&#111;&#111;&#46;&#99;&#111;&#109;"><u><font color=#0000ff>mount0n@yahoo.com</font></u></a>和他联系。<br></p>
<img height=1 src="http://www.moon-soft.com/doc/down_info.asp?id=39077" width=1 border=0><br>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/121339.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-06-01 13:17 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/06/01/121339.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Graphviz &amp; Doxygen コード構造を視覚化せよ！！</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/06/01/121338.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 01 Jun 2007 05:07:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/06/01/121338.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/121338.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/06/01/121338.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/121338.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/121338.html</trackback:ping><description><![CDATA[<h2 align=center>コード構造を視覚化せよ！！<br>Graphviz &amp; Doxygen</h2>
<hr>
<p><a href="http://skazami.web.infoseek.co.jp/tools/Graphviz_Doxygen.htm">http://skazami.web.infoseek.co.jp/tools/Graphviz_Doxygen.htm</a><br><br><br><br><br>コードの構造を視覚化するためのツールです。コード解析に有効かどうかはともかく、なかなか面白いツールです。<br><br>それぞれのツールのサイト（たぶん、公式サイト）はこちら。<br><br><a href="http://www.research.att.com/sw/tools/graphviz/"><font color=#0000ff><u>Graphviz</u></font></a><br><a href="http://www.stack.nl/~dimitri/doxygen/"><u><font color=#0000ff>Doxygen</font></u></a><br><br>どちらもオープンソースですので、開発に参加することもできるようです。Doxygenは寄付も受け付けているようです。</p>
<p>前置きはこのくらいにして、説明いきます。</p>
<hr>
<h3>インストール</h3>
<p>自分のプラットフォームにあったパッケージをダウンロードします。Linux用、Windows用、Mac用などあります。</p>
<p>Graphvizは、上記サイト内にある<a href="http://www.research.att.com/sw/tools/graphviz/download.html"><u><font color=#0000ff>download</font></u></a>をクリックして、パッケージを持ってきます。<br>Doxygenも、上記サイトの右のほうにある<a href="http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc"><u><font color=#0000ff>Binaries</font></u></a>をクリックして、パッケージを持ってきます。<br><br>インストールは<strong>必ずGraphviz&#8594;Doxygenの順番</strong>で行います。<br><br>以下の説明はWindows用についてのものです。<br>インストールはインストーラ（exeファイル）を起動してウィザードに従うだけなので、悩むこともないと思います。</p>
<dl>
<dt><strong>ステップバイステップインストール手順</strong>（<a href="http://skazami.web.infoseek.co.jp/tools/graphviz/graphviz_install.htm"><u><font color=#0000ff>Graphviz</font></u></a>、<a href="http://skazami.web.infoseek.co.jp/tools/doxygen/doxygen_install.htm"><u><font color=#0000ff>Doxygen</font></u></a>）
<dd>インストール慣れしている方はスキップしてください。ほとんどデフォルトでのインストールですので。どちらかと言うと、自分用作業メモです。 </dd></dl>
<hr>
<h3>使用法</h3>
<ol>
    <li>インストール時に入れておいた「doxygen example Project」を例にコードの構造を視覚化してみます
    <li>「スタート」&#8594;「プログラム」&#8594;「doxygen」&#8594;「Doxywizard」を起動します。このツールにより、設定ファイルの作成とDoxygenの実行をGUIから行うことができます。
    <p><a href="http://skazami.web.infoseek.co.jp/tools/doxygen/image/doxygen01.jpg"><img height=253 src="http://skazami.web.infoseek.co.jp/tools/doxygen/image_small/doxygen01.jpg" width=324 border=0></a><br></p>
    <li>OUTPUT_LANGUAGEを「Japanese」にします
    <p><a href="http://skazami.web.infoseek.co.jp/tools/doxygen/image/doxygen02.jpg"><img height=253 src="http://skazami.web.infoseek.co.jp/tools/doxygen/image_small/doxygen02.jpg" width=324 border=0></a><br></p>
    <li>Buildタブをクリックし、「EXTRACT_ALL」にチェックを入れます
    <p><a href="http://skazami.web.infoseek.co.jp/tools/doxygen/image/doxygen04.jpg"><img height=253 src="http://skazami.web.infoseek.co.jp/tools/doxygen/image_small/doxygen04.jpg" width=324 border=0></a><br></p>
    <li>LaTeXタブをクリックし、「GENERATE_LATEX」のチェックを外します。もちろん、LaTeXの出力が必要ならチェックを入れておいてください
    <p><a href="http://skazami.web.infoseek.co.jp/tools/doxygen/image/doxygen06.jpg"><img height=253 src="http://skazami.web.infoseek.co.jp/tools/doxygen/image_small/doxygen06.jpg" width=324 border=0></a><br></p>
    <li>Dotタブをクリックし、「HAVE_DOT」にチェックを入れます
    <p><a href="http://skazami.web.infoseek.co.jp/tools/doxygen/image/doxygen08.jpg"><img height=253 src="http://skazami.web.infoseek.co.jp/tools/doxygen/image_small/doxygen08.jpg" width=324 border=0></a><br></p>
    <li>「CALL_GRAPH」にもチェックを入れときます。関数の呼び出し状況を図にしてくれます。
    <p><a href="http://skazami.web.infoseek.co.jp/tools/doxygen/image/doxygen09.jpg"><img height=253 src="http://skazami.web.infoseek.co.jp/tools/doxygen/image_small/doxygen09.jpg" width=324 border=0></a><br></p>
    <li>「File」&#8594;「Save as...」で設定ファイルを保存しますが、保存先は<strong>「C:\Program Files\doxygen\examples」（デフォルト設定でインストールした場合）</strong>としてください。ファイル名は何でもいいですが、とりあえず「Doxyfile」とでもしておきましょう
    <p><br></p>
    <li>「Doxygen」&#8594;「Run」で実行します。コンソールが出現し、処理が進みます
    <p><a href="http://skazami.web.infoseek.co.jp/tools/doxygen/image/doxygen10.jpg"><img height=241 src="http://skazami.web.infoseek.co.jp/tools/doxygen/image_small/doxygen10.jpg" width=334 border=0></a></p>
    <li><strong>「C:\Program Files\doxygen\examples」</strong>にhtmlというフォルダが作成されます。そのフォルダの中のindex.htmlを開いてみます
    <p><a href="http://skazami.web.infoseek.co.jp/tools/doxygen/image/doxygen11.jpg"><img height=360 src="http://skazami.web.infoseek.co.jp/tools/doxygen/image_small/doxygen11.jpg" width=446 border=0></a><br><br>どうでしょう、こんな画面になりましたか？</p>
    <li>「ファイル一覧」&#8594;example_test.cppを開いてみてください。関数の呼び出しグラフが表示されましたか？グラフがクリッカブルマップになっていますか？
    <li>「ファイル一覧」&#8594;diagrams_a.hを開いてみてください。ファイルの依存関係のグラフが表示されましたか？グラフがクリッカブルマップになっていますか？ </li>
</ol>
<p>問題がなければ、基本的な使い方は以上です。あとはマニュアルを読みながら高度な使い方を模索してください。私自身、あまり高度な使い方はできていないので、面白い使い方があったら教えていただきたいです。<br><br>Doxygenのマニュアルを日本語化している方がいらっしゃるようです。<br><a href="http://www.fides.dti.ne.jp/~oka-t/doxygen-manual/html/"><u><font color=#0000ff>http://www.fides.dti.ne.jp/~oka-t/doxygen-manual/html/</font></u></a></p>
<u><font color=#0000ff>
<hr>
</font></u>
<h3><strong>Doxygenで変換した結果の例</strong></h3>
<p>私が変換してみたものを以下に置いておきます。同じような感じになっているかどうかを確認するために使ってみてください。</p>
<p><a href="http://skazami.web.infoseek.co.jp/tools/doxygen/doxygen_example_html/index.html"><font color=#0000ff><u>doxygen付属のexampleプロジェクト</u></font></a><br><br><a href="http://skazami.web.infoseek.co.jp/tools/doxygen/VSdotNet2003_Plain_html/index.html"><u><font color=#0000ff>デフォルト設定で作成直後のWin32アプリケーションプロジェクト</font></u></a>（作成環境はVisual Studio .net 2003）</p>
<p>[余談]<br>doxygenのexampleプロジェクトの変換結果で、「関連ページ」&#8594;「バグ一覧」&#8594;「WindowsNT」は、あからさま過ぎるくらいあからさまで、まぁまぁ面白いです。これ以上のコメントは控えます。<br>[余談終]</p>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/121338.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-06-01 13:07 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/06/01/121338.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Doxygen的使用体会 (zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/06/01/121337.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 01 Jun 2007 05:06:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/06/01/121337.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/121337.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/06/01/121337.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/121337.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/121337.html</trackback:ping><description><![CDATA[<span class=vcer>&nbsp;
<p>Doxygen的使用体会 </p>
<p>&#160;</p>
<p>Doxygen是一款开源软件，可用于从已经存在的VC工程中提炼出软件文档（HTML等格式），包括文件说明、类说明、属性方法说明、类关系等内容。一般常将Doxygen和graphviz两款软件一起安装，后者是一款绘图软件，可在前者生成的软件文档中增加图表。Doxygen的细节可以上网搜索。这里贴一下个人体会，可帮助感兴趣的朋友迅速上手这个软件： </p>
<p>1，安装DOXYGEN和graphviz后，可以在&#8220;DOXYGEN安装目录\bin&#8221;下用命令行方式运行doxygen.exe -g 生成一个名为Doxyfile的配置文件。 </p>
<p>2，将文件Doxyfile复制到想生成文档的VC工程目录下。 </p>
<p>修改该文件中的如下选项： </p>
<p>
<div class=dp-highlighter>
<div class=bar>
<div class=tools><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" href="http://vcer.net/6399.html#"><img src="http://vcer.net/images/edit.gif" align=absBottom border=0><img width=4 border=0><u>查看源代码</u></a><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://vcer.net/6399.html#"><u><img src="http://vcer.net/images/paste.gif" align=absBottom border=0><img width=4 border=0>拷贝至剪贴板</u></a><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" href="http://vcer.net/6399.html#"><u><img src="http://vcer.net/images/print.gif" align=absBottom border=0><img width=4 border=0>打印代码</u></a></div>
</div>
<ol class=dp-cpp>
    <li class=alt><span><span>PROJECT_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;填上项目名称&nbsp; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>OUTPUT_LANGUAGE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;改为Chinese&nbsp; &nbsp;&nbsp;</span></li>
    <li class=alt><span>GENERATE_LATEX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;改为NO&nbsp; &nbsp;&nbsp;</span></li>
    <li class=""><span>EXTRACT_ALL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;改为YES&nbsp; &nbsp;&nbsp;</span></li>
    <li class=alt><span>HAVE_DOT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;改为YES&nbsp; &nbsp;&nbsp;</span></li>
    <li class=""><span>DOT_IMAGE_FORMAT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;该为JPG&nbsp; &nbsp;&nbsp;</span></li>
    <li class=alt><span>DOT_PATH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;填上</span><span class=string>"C:/Program&nbsp;Files/ATT/Graphviz/bin/"</span><span>&nbsp; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>DOTFILE_DIRS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;填上</span><span class=string>"c:/Program&nbsp;Files/ATT/Graphviz/bin/"</span><span>&nbsp;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<textarea class=cpp style="DISPLAY: none" readOnly>PROJECT_NAME          = 填上项目名称
OUTPUT_LANGUAGE        = 改为Chinese
GENERATE_LATEX        = 改为NO
EXTRACT_ALL            = 改为YES
HAVE_DOT              = 改为YES
DOT_IMAGE_FORMAT      = 该为JPG
DOT_PATH              = 填上"C:/Program Files/ATT/Graphviz/bin/"
DOTFILE_DIRS          = 填上"c:/Program Files/ATT/Graphviz/bin/" </textarea>
<p>&#160;</p>
<p>3，对VC工程进行如下修改 </p>
<p>（1）在stdAfx.h中增加预定义，以支持DOT画图。 </p>
<p>
<div class=dp-highlighter>
<div class=bar>
<div class=tools><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" href="http://vcer.net/6399.html#"><img src="http://vcer.net/images/edit.gif" align=absBottom border=0><img width=4 border=0><u>查看源代码</u></a><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://vcer.net/6399.html#"><u><img src="http://vcer.net/images/paste.gif" align=absBottom border=0><img width=4 border=0>拷贝至剪贴板</u></a><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" href="http://vcer.net/6399.html#"><u><img src="http://vcer.net/images/print.gif" align=absBottom border=0><img width=4 border=0>打印代码</u></a></div>
</div>
<ol class=dp-cpp>
    <li class=alt><span><span class=preprocessor>#ifndef&nbsp;_DIAGRAMS_A_H&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span></span><span class=preprocessor>#define&nbsp;_DIAGRAMS_A_H&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li class=alt><span></span><span class=preprocessor>#endif&nbsp;</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<textarea class=cpp style="DISPLAY: none" readOnly>#ifndef _DIAGRAMS_A_H
#define _DIAGRAMS_A_H
#endif </textarea>
<p>&#160;</p>
<p>（2）在重要的类、方法、属性前面增加注释，以支持DOXYGEN分析。 </p>
<p>
<div class=dp-highlighter>
<div class=bar>
<div class=tools><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" href="http://vcer.net/6399.html#"><img src="http://vcer.net/images/edit.gif" align=absBottom border=0><img width=4 border=0><u>查看源代码</u></a><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://vcer.net/6399.html#"><u><img src="http://vcer.net/images/paste.gif" align=absBottom border=0><img width=4 border=0>拷贝至剪贴板</u></a><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" href="http://vcer.net/6399.html#"><u><img src="http://vcer.net/images/print.gif" align=absBottom border=0><img width=4 border=0>打印代码</u></a></div>
</div>
<ol class=dp-cpp>
    <li class=alt><span><span class=comment>///&nbsp;&nbsp;&nbsp;&nbsp;@brief&nbsp;最主要的业务实现类&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span></span><span class=comment>///&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li class=alt><span></span><span class=comment>///&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;所有的算法内容基本都在这个类中实现。&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span></span><span class=comment>///&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li class=alt><span></span><span class=comment>///&nbsp;&nbsp;&nbsp;&nbsp;@author&nbsp;lipp&nbsp;</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<textarea class=cpp style="DISPLAY: none" readOnly>///    @brief 最主要的业务实现类
///
///            所有的算法内容基本都在这个类中实现。
///
///    @author lipp </textarea>
<p>&#160;</p>
<p>或者放在语句后面
<div class=dp-highlighter>
<div class=bar>
<div class=tools><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" href="http://vcer.net/6399.html#"><img src="http://vcer.net/images/edit.gif" align=absBottom border=0><img width=4 border=0><u>查看源代码</u></a><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://vcer.net/6399.html#"><u><img src="http://vcer.net/images/paste.gif" align=absBottom border=0><img width=4 border=0>拷贝至剪贴板</u></a><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" href="http://vcer.net/6399.html#"><u><img src="http://vcer.net/images/print.gif" align=absBottom border=0><img width=4 border=0>打印代码</u></a></div>
</div>
<ol class=dp-cpp>
    <li class=alt><span><span class=datatypes>char</span><span>&nbsp;sFilename[400];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment>///&lt;&nbsp;LOG文件名&nbsp;</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<textarea class=cpp style="DISPLAY: none" readOnly>        char sFilename[400];            ///&lt; LOG文件名 </textarea>
<p>&#160;</p>
<p>并在重要文件前增加注释 </p>
<p>
<div class=dp-highlighter>
<div class=bar>
<div class=tools><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" href="http://vcer.net/6399.html#"><img src="http://vcer.net/images/edit.gif" align=absBottom border=0><img width=4 border=0><u>查看源代码</u></a><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://vcer.net/6399.html#"><u><img src="http://vcer.net/images/paste.gif" align=absBottom border=0><img width=4 border=0>拷贝至剪贴板</u></a><a style="COLOR: #666666" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" href="http://vcer.net/6399.html#"><u><img src="http://vcer.net/images/print.gif" align=absBottom border=0><img width=4 border=0>打印代码</u></a></div>
</div>
<ol class=dp-cpp>
    <li class=alt><span><span class=comment>///&nbsp;&nbsp;&nbsp;&nbsp;@file&nbsp;xxx.cpp&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span></span><span class=comment>///&nbsp;&nbsp;&nbsp;&nbsp;被其他程序调用的，实现了算法的DLL主程序。&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li class=alt><span></span><span class=comment>///&nbsp;&nbsp;&nbsp;&nbsp;包括各个方法输出接口。&nbsp;</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<textarea class=cpp style="DISPLAY: none" readOnly>///    @file xxx.cpp
///    被其他程序调用的，实现了算法的DLL主程序。
///    包括各个方法输出接口。 </textarea>
<p>&#160;</p>
<p>4，运行DOXYGEN.exe。LOAD以上的Doxyfile文件。点击START。这时会生成一个新的HTML目录在VC工程目录中。 </p>
<p>5，使用IE打开新生成的HTML目录中的INDEX.htm文件。 </p>
<p>&#160;</p>
</span>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/121337.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-06-01 13:06 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/06/01/121337.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Endian  介绍 (zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120455.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Mon, 28 May 2007 07:08:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120455.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/120455.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120455.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/120455.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/120455.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://www.blogjava.net/Files/jinfeng_wang/Endian.rarEndian&nbsp; 介绍1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Endian简介Endian可以看作是系统的一种属性, 它指示多字节整数是从左向右放, 还是从右向左放. 它有两种形式: &nbsp;&nbsp;&nbsp;&nbsp...&nbsp;&nbsp;<a href='http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120455.html'>阅读全文</a><img src ="http://www.blogjava.net/jinfeng_wang/aggbug/120455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-05-28 15:08 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>automake:自动生成makefile文件 (zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120428.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Mon, 28 May 2007 04:37:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120428.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/120428.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120428.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/120428.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/120428.html</trackback:ping><description><![CDATA[&nbsp; Makefile是用于自动编译和链接的，一个工程有很多文件组成，每一个文件的改变都会导致工程的重新链接，但是不是所有的文件都需要重新编译，Makefile中纪录有文件的信息，在make时会决定在链接的时候需要重新编译哪些文件。
<p>　　Makefile的宗旨就是：让编译器知道要编译一个文件需要依赖其他的哪些文件。当那些依赖文件有了改变，编译器会自动的发现最终的生成文件已经过时，而重新编译相应的模块。</p>
<p>　　Makefile的基本结构不是很复杂，但当一个程序开发人员开始写Makefile时，经常会怀疑自己写的是否符合惯例，而且自己写的Makefile经常和自己的开发环境相关联，当系统环境变量或路径发生了变化后，Makefile可能还要跟着修改。这样就造成了手工书写Makefile的诸多问题，automake恰好能很好地帮助我们解决这些问题。</p>
<p>　　使用automake，程序开发人员只需要写一些简单的含有预定义宏的文件，由autoconf根据一个宏文件生成configure，由automake根据另一个宏文件生成Makefile.in，再使用configure依据Makefile.in来生成一个符合惯例的Makefile。下面我们将详细介绍Makefile的automake生成方法。</p>
<p>　　二、使用的环境</p>
<p>　　本文所提到的程序是基于Linux发行版本：Fedora Core release 1，它包含了我们要用到的autoconf，automake。</p>
<p>　　三、从helloworld入手</p>
<p>　　我们从大家最常使用的例子程序helloworld开始。</p>
<p>　　下面的过程如果简单地说来就是：</p>
<p>　　新建三个文件：</p>
<p>　　　helloworld.c<br>　　　configure.in<br>　　　Makefile.am</p>
<p>　　然后执行：</p>
<p>aclocal; autoconf; automake --add-missing; ./configure; make; ./helloworld </p>
<p>　　就可以看到Makefile被产生出来，而且可以将helloworld.c编译通过。</p>
<p>　　很简单吧，几条命令就可以做出一个符合惯例的Makefile，感觉如何呀。</p>
<p>　　现在开始介绍详细的过程：</p>
<p>　　1、建目录</p>
<p>　　在你的工作目录下建一个helloworld目录，我们用它来存放helloworld程序及相关文件，如在/home/my/build下：</p>
<p>$ mkdir helloword<br>$ cd helloworld </p>
<p>　　2、 helloworld.c</p>
<p>　　然后用你自己最喜欢的编辑器写一个hellowrold.c文件，如命令：vi helloworld.c。使用下面的代码作为helloworld.c的内容。</p>
<p>int main(int argc, char** argv)<br>{<br>printf("Hello, Linux World!\n");<br>return 0;<br>} </p>
<p>　　完成后保存退出。</p>
<p>　　现在在helloworld目录下就应该有一个你自己写的helloworld.c了。</p>
<p>　　3、生成configure</p>
<p>　　我们使用autoscan命令来帮助我们根据目录下的源代码生成一个configure.in的模板文件。</p>
<p>　　命令：</p>
<p>$ autoscan<br>$ ls<br>configure.scan helloworld.c </p>
<p>　　执行后在hellowrold目录下会生成一个文件：configure.scan，我们可以拿它作为configure.in的蓝本。</p>
<p>　　现在将configure.scan改名为configure.in，并且编辑它，按下面的内容修改，去掉无关的语句：</p>
<p>============================configure.in内容开始=========================================<br># -*- Autoconf -*-<br># Process this file with autoconf to produce a configure script.</p>
<p>AC_INIT(helloworld.c)<br>AM_INIT_AUTOMAKE(helloworld, 1.0)</p>
<p># Checks for programs.<br>AC_PROG_CC</p>
<p># Checks for libraries.</p>
<p># Checks for header files.</p>
<p># Checks for typedefs, structures, and compiler characteristics.</p>
<p># Checks for library functions.<br>AC_OUTPUT(Makefile)<br>============================configure.in内容结束========================================= </p>
<p>　　然后执行命令aclocal和autoconf，分别会产生aclocal.m4及configure两个文件：</p>
<p>$ aclocal <br>$ls <br>aclocal.m4 configure.in helloworld.c <br>$ autoconf <br>$ ls <br>aclocal.m4 autom4te.cache configure configure.in helloworld.c </p>
<p><br>　　大家可以看到configure.in内容是一些宏定义，这些宏经autoconf处理后会变成检查系统特性、环境变量、软件必须的参数的shell脚本。</p>
<p>　　autoconf 是用来生成自动配置软件源代码脚本（configure）的工具。configure脚本能独立于autoconf运行，且在运行的过程中，不需要用户的干预。</p>
<p>　　要生成configure文件，你必须告诉autoconf如何找到你所用的宏。方式是使用aclocal程序来生成你的aclocal.m4。</p>
<p>　　aclocal根据configure.in文件的内容，自动生成aclocal.m4文件。aclocal是一个perl 脚本程序，它的定义是：&#8220;aclocal - create aclocal.m4 by scanning configure.ac&#8221;。</p>
<p>　　autoconf从configure.in这个列举编译软件时所需要各种参数的模板文件中创建configure。</p>
<p>　　autoconf需要GNU m4宏处理器来处理aclocal.m4，生成configure脚本。</p>
<p>　　m4是一个宏处理器。将输入拷贝到输出，同时将宏展开。宏可以是内嵌的，也可以是用户定义的。除了可以展开宏，m4还有一些内建的函数，用来引用文件，执行命令，整数运算，文本操作，循环等。m4既可以作为编译器的前端，也可以单独作为一个宏处理器。</p>
<p>4、新建Makefile.am</p>
<p>　　新建Makefile.am文件，命令：</p>
<p><br>$ vi Makefile.am </p>
<p><br>　　内容如下:</p>
<p><br>AUTOMAKE_OPTIONS=foreign<br>bin_PROGRAMS=helloworld<br>helloworld_SOURCES=helloworld.c </p>
<p><br>　　automake会根据你写的Makefile.am来自动生成Makefile.in。</p>
<p>　　Makefile.am中定义的宏和目标,会指导automake生成指定的代码。例如，宏bin_PROGRAMS将导致编译和连接的目标被生成。</p>
<p>　　5、运行automake</p>
<p>　　命令：</p>
<p><br>$ automake --add-missing<br>configure.in: installing `./install-sh'<br>configure.in: installing `./mkinstalldirs'<br>configure.in: installing `./missing'<br>Makefile.am: installing `./depcomp' </p>
<p><br>　　automake会根据Makefile.am文件产生一些文件，包含最重要的Makefile.in。</p>
<p>　　6、执行configure生成Makefile</p>
<p><br>$ ./configure <br>checking for a BSD-compatible install... /usr/bin/install -c<br>checking whether build environment is sane... yes<br>checking for gawk... gawk<br>checking whether make sets $(MAKE)... yes<br>checking for gcc... gcc<br>checking for C compiler default output... a.out<br>checking whether the C compiler works... yes<br>checking whether we are cross compiling... no<br>checking for suffix of executables... <br>checking for suffix of object files... o<br>checking whether we are using the GNU C compiler... yes<br>checking whether gcc accepts -g... yes<br>checking for gcc option to accept ANSI C... none needed<br>checking for style of include used by make... GNU<br>checking dependency style of gcc... gcc3<br>configure: creating ./config.status<br>config.status: creating Makefile<br>config.status: executing depfiles commands<br>$ ls -l Makefile<br>-rw-rw-r-- 1 yutao yutao 15035 Oct 15 10:40 Makefile </p>
<p><br>你可以看到，此时Makefile已经产生出来了。</p>
<p>7、使用Makefile编译代码</p>
<p>&nbsp;</p>
<p>$ make<br>if gcc -DPACKAGE_NAME="" -DPACKAGE_TARNAME="" -DPACKAGE_VERSION="" -</p>
<p>DPACKAGE_STRING="" -DPACKAGE_BUGREPORT="" -DPACKAGE="helloworld" -DVERSION="1.0" </p>
<p>-I. -I. -g -O2 -MT helloworld.o -MD -MP -MF ".deps/helloworld.Tpo" \<br>-c -o helloworld.o `test -f 'helloworld.c' || echo './'`helloworld.c; \<br>then mv -f ".deps/helloworld.Tpo" ".deps/helloworld.Po"; \<br>else rm -f ".deps/helloworld.Tpo"; exit 1; \<br>fi<br>gcc -g -O2 -o helloworld helloworld.o&nbsp; </p>
<p><br>　　运行helloworld</p>
<p>&nbsp;</p>
<p>$ ./helloworld <br>Hello, Linux World! </p>
<p><br>　　这样helloworld就编译出来了，你如果按上面的步骤来做的话，应该也会很容易地编译出正确的helloworld文件。你还可以试着使用一些其他的make命令，如make clean，make install，make dist，看看它们会给你什么样的效果。感觉如何？自己也能写出这么专业的Makefile，老板一定会对你刮目相看。</p>
<p>　　四、深入浅出</p>
<p>　　针对上面提到的各个命令，我们再做些详细的介绍。</p>
<p>　　1、 autoscan</p>
<p>　　autoscan是用来扫描源代码目录生成configure.scan文件的。autoscan可以用目录名做为参数，但如果你不使用参数的话，那么autoscan将认为使用的是当前目录。autoscan将扫描你所指定目录中的源文件，并创建configure.scan文件。</p>
<p>　　2、 configure.scan</p>
<p>　　configure.scan包含了系统配置的基本选项，里面都是一些宏定义。我们需要将它改名为configure.in</p>
<p>　　3、 aclocal</p>
<p>　　aclocal是一个perl 脚本程序。aclocal根据configure.in文件的内容，自动生成aclocal.m4文件。aclocal的定义是：&#8220;aclocal - create aclocal.m4 by scanning configure.ac&#8221;。</p>
<p>　　4、 autoconf</p>
<p>　　autoconf是用来产生configure文件的。configure是一个脚本，它能设置源程序来适应各种不同的操作系统平台，并且根据不同的系统来产生合适的Makefile，从而可以使你的源代码能在不同的操作系统平台上被编译出来。</p>
<p>　　configure.in文件的内容是一些宏，这些宏经过autoconf 处理后会变成检查系统特性、环境变量、软件必须的参数的shell脚本。configure.in文件中的宏的顺序并没有规定，但是你必须在所有宏的最前面和最后面分别加上AC_INIT宏和AC_OUTPUT宏。</p>
<p>　　在configure.ini中：</p>
<p>　　#号表示注释，这个宏后面的内容将被忽略。</p>
<p>　　AC_INIT(FILE) </p>
<p>　　这个宏用来检查源代码所在的路径。</p>
<p>AM_INIT_AUTOMAKE(PACKAGE, VERSION)&nbsp; </p>
<p>　　 这个宏是必须的，它描述了我们将要生成的软件包的名字及其版本号：PACKAGE是软件包的名字，VERSION是版本号。当你使用make dist命令时，它会给你生成一个类似helloworld-1.0.tar.gz的软件发行包，其中就有对应的软件包的名字和版本号。</p>
<p>AC_PROG_CC</p>
<p>　　这个宏将检查系统所用的C编译器。 </p>
<p>AC_OUTPUT(FILE)</p>
<p>　　这个宏是我们要输出的Makefile的名字。</p>
<p>　　我们在使用automake时，实际上还需要用到其他的一些宏，但我们可以用aclocal 来帮我们自动产生。执行aclocal后我们会得到aclocal.m4文件。</p>
<p>　　产生了configure.in和aclocal.m4 两个宏文件后，我们就可以使用autoconf来产生configure文件了。</p>
<p>　　5、 Makefile.am</p>
<p>　　Makefile.am是用来生成Makefile.in的，需要你手工书写。Makefile.am中定义了一些内容：</p>
<p>AUTOMAKE_OPTIONS </p>
<p>　　这个是automake的选项。在执行automake时，它会检查目录下是否存在标准GNU软件包中应具备的各种文件，例如AUTHORS、ChangeLog、NEWS等文件。我们将其设置成foreign时，automake会改用一般软件包的标准来检查。</p>
<p>bin_PROGRAMS</p>
<p>　　这个是指定我们所要产生的可执行文件的文件名。如果你要产生多个可执行文件，那么在各个名字间用空格隔开。 </p>
<p>helloworld_SOURCES </p>
<p>　　这个是指定产生&#8220;helloworld&#8221;时所需要的源代码。如果它用到了多个源文件，那么请使用空格符号将它们隔开。比如需要helloworld.h，helloworld.c那么请写成helloworld_SOURCES= helloworld.h helloworld.c。</p>
<p>　　如果你在bin_PROGRAMS定义了多个可执行文件，则对应每个可执行文件都要定义相对的filename_SOURCES。</p>
<p>　　6、 automake</p>
<p>　　我们使用automake --add-missing来产生Makefile.in。</p>
<p>　　选项--add-missing的定义是&#8220;add missing standard files to package&#8221;，它会让automake加入一个标准的软件包所必须的一些文件。</p>
<p>　　我们用automake产生出来的Makefile.in文件是符合GNU Makefile惯例的，接下来我们只要执行configure这个shell 脚本就可以产生合适的 Makefile 文件了。</p>
<p>　　7、 Makefile</p>
<p>　　在符合GNU Makefiel惯例的Makefile中，包含了一些基本的预先定义的操作：</p>
<p>make</p>
<p>　　根据Makefile编译源代码，连接，生成目标文件，可执行文件。</p>
<p>make clean</p>
<p>　　清除上次的make命令所产生的object文件（后缀为&#8220;.o&#8221;的文件）及可执行文件。</p>
<p>make install</p>
<p>　　将编译成功的可执行文件安装到系统目录中，一般为/usr/local/bin目录。</p>
<p>make dist</p>
<p>　　产生发布软件包文件（即distribution package）。这个命令将会将可执行文件及相关文件打包成一个tar.gz压缩的文件用来作为发布软件的软件包。</p>
<p>　　它会在当前目录下生成一个名字类似&#8220;PACKAGE-VERSION.tar.gz&#8221;的文件。PACKAGE和VERSION，是我们在configure.in中定义的AM_INIT_AUTOMAKE(PACKAGE, VERSION)。</p>
<p>make distcheck</p>
<p>　　生成发布软件包并对其进行测试检查，以确定发布包的正确性。这个操作将自动把压缩包文件解开，然后执行configure命令，并且执行make，来确认编译不出现错误，最后提示你软件包已经准备好，可以发布了。</p>
<p>===============================================<br>helloworld-1.0.tar.gz is ready for distribution<br>===============================================<br>make distclean </p>
<p>　　类似make clean，但同时也将configure生成的文件全部删除掉，包括Makefile。</p>
<p>　　五、结束语</p>
<p>　　通过上面的介绍，你应该可以很容易地生成一个你自己的符合GNU惯例的Makefile文件及对应的项目文件。</p>
<p>　　如果你想写出更复杂的且符合惯例的Makefile，你可以参考一些开放代码的项目中的configure.in和Makefile.am文件，比如：嵌入式数据库sqlite，单元测试cppunit。 </p>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/120428.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-05-28 12:37 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120428.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Window+GCC+CDT用Eclipse開發C、C++ (zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120421.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Mon, 28 May 2007 04:00:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120421.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/120421.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120421.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/120421.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/120421.html</trackback:ping><description><![CDATA[<a href="http://www.javaworld.com.tw/jute/post/view?bid=10&amp;id=53262&amp;sty=1&amp;tpg=1&amp;age=0">http://www.javaworld.com.tw/jute/post/view?bid=10&amp;id=53262&amp;sty=1&amp;tpg=1&amp;age=0</a><br><br><br>Eclipse除了可以開發Java之外，還支援了許多語言，現在先介紹 <br>C、C++的開發環境設定，以後有機會再介紹其它的。Enjoy it！ <br><br>OS：Windows XP Professional SP1 <br>使用版本：Eclipse 2.1.2 <br><br>一.首先要下載CDT，Eclipse 2.1.2使用者，請下載這項： <br>CDT 1.2 Full for Windows R2.1.1 1.2.0 GA - Full - Windows。 <br>Eclipse 2.1.3使用者請下載：CDT 1.2.1。 <br>Eclipse 3.0 M7使用者請下載：CDT 2.0 M7。 <br>Eclipse 3.0 M8使用者請下載：CDT 2.0 M8。 <br>Eclipse 3.0 M9使用者請下載：CDT 2.0 M9。 <br>下載網址：<a class=ilink href="http://www.eclipse.org/cdt/" target=_blank><u><font color=#0000ff>http://www.eclipse.org/cdt/</font></u></a> <br><br>安裝：將解壓縮後的features、plugins整個資料夾複製到Eclipse安裝資料 <br>裡，重新開啟Eclipse即可。 <br><br>二.下載可在Windows上使用的GNU C、C++編譯器，這裡要下載的是：MinGW。 <br>Download頁面很長的一串，請選擇這個版本： <br><font color=red>MinGW bin MinGW-3.1.0-1.exe 14863 kb Sep 15, 2003 11:14</font> <br>下載網址：<a class=ilink href="http://www.mingw.org/download.shtml" target=_blank><u><font color=#0000ff>http://www.mingw.org/download.shtml</font></u></a> <br><br>安裝：安裝目錄選C槽，然後狂點下一步(Next)就行了。安裝完後路徑是這 <br>樣-&gt;C:\MinGW。 <br><br>三.先在Command Line模式下測試編譯與執行。先將C:\MinGW\bin底下的 <br>mingw32-make.exe更名為make.exe，因為待會在Eclipse使用時它預設 <br>會抓系統裡make這個檔名而不是mingw32-make。 <br><br><font color=hotpink>(註：如果不更名或是還有其他make程式時，也可以在稍後的Eclipse設定 <br>中，在make targets view的地方，新增一個task時，build command 取消 <br>use default , 使用 mingw32-make，或在project properties-&gt;make project -&gt; <br>將make 改為 mingw32-make ) </font><font color=red>-- 由<strong> snpshu</strong> 補充。</font> <br><br>在環境變數裡加入下列設定： <br>PATH ： C:\MinGW\bin; (如果系統已經有裝其它C/C++編譯器，請把C:\MinGW\bin加在最前面。) <br>LIBRARY_PATH ：C:\MinGW\lib <br>C_INCLUDE_PATH ：C:\MinGW\include <br>CPLUS_INCLUDE_PATH ：C:\MinGW\include\c++\3.2.3;C:\MinGW\include\c++\3.2.3\mingw32; <br>C:\MinGW\include\c++\3.2.3\backward;C:\MinGW\include <br><br>先使用文字編輯器編寫測試用的原始檔，檔名：main.cpp。 <br>
<table class=java cellSpacing=1 cellPadding=3 bgColor=#999999 border=0>
    <tbody>
        <tr>
            <td vAlign=top align=left width=1 bgColor=#dddddd>
            <pre><font color=#555555>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br></font></pre>
            </td>
            <td vAlign=top align=left bgColor=#ffffff>
            <pre>#include &lt;iostream&gt;
            using namespace std;
            &nbsp;
            <font class=java-reserved_word><strong>int</strong></font> main(<font class=java-reserved_word><strong>void</strong></font>) <font class=java-bracket>{</font>
            cout &lt;&lt; <font class=java-string>"Can You Feel My World？"</font> ;
            &nbsp;
            <font class=java-reserved_word><strong>return</strong></font> 0;
            <font class=java-bracket>}</font>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>在Command Line下編譯指令：
<table class=java cellSpacing=1 cellPadding=3 bgColor=#999999 border=0>
    <tbody>
        <tr>
            <td vAlign=top align=left width=1 bgColor=#dddddd>
            <pre><font color=#555555>1<br></font></pre>
            </td>
            <td vAlign=top align=left bgColor=#ffffff>
            <pre>C:\g++ main.cpp -O3 -o hello
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>(O3的O是英文大寫"歐") <br>編譯成功後：便會產生hello.exe的執行檔。 <br>執行畫面如下：
<table class=java cellSpacing=1 cellPadding=3 bgColor=#999999 border=0>
    <tbody>
        <tr>
            <td vAlign=top align=left width=1 bgColor=#dddddd>
            <pre><font color=#555555>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>10<br></font></pre>
            </td>
            <td vAlign=top align=left bgColor=#ffffff>
            <pre>Microsoft Windows XP [版本 5.1.2600]
            (C) Copyright 1985-2001 Microsoft Corp.
            &nbsp;
            C:\Documents and Settings\Sungo&gt;cd\
            &nbsp;
            C:\&gt;g++ main.cpp -O3 -o hello
            &nbsp;
            C:\&gt;hello
            Can You Feel My World？
            C:\&gt;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>註：-O3 旗標表示採最高級編譯最佳化，編譯速度最慢，但產生的執行檔 <br>檔案會最小，執行速度會最快；-o 旗標表示將編譯完的*.exe重新更名。 <br><br>◎步驟一.開啟Eclipse後，首先先開啟C/C++專用視景。 <br>Windows-&gt;Open Perspective-&gt;C/C++ Development <br><br>◎步驟二.建立一個C++用的專案。 <br>File-New-&gt;Project-&gt;C++-&gt;Standard Make C++ Project <br>(接下來的步驟跟建立一般的Java專案一樣，皆採預設即可) <br><br>◎步驟三.把我們剛剛寫的main.cpp import進來，加到專案裡。 <br>File-&gt;Import-&gt;File System-&gt;瀏覽C:\main.cpp <br><br>◎步驟四.建立一個makefile。 <br>File-&gt;New-&gt;File，檔案名稱填：makefile。(不需打副檔名) <br><br>makefile內容如下：
<table class=java cellSpacing=1 cellPadding=3 bgColor=#999999 border=0>
    <tbody>
        <tr>
            <td vAlign=top align=left width=1 bgColor=#dddddd>
            <pre><font color=#555555>1<br>2<br></font></pre>
            </td>
            <td vAlign=top align=left bgColor=#ffffff>
            <pre>all:
            g++  main.cpp -g -o run
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br><font color=red>注意：makefile縮排要以Tab鍵作縮排，不能以空格4作縮排， <br>否則Build會有問題。</font> <br><br>◎步驟五.設定Make Targets。 <br>Windows-Show View-&gt;Make Targets <br>在Make Targets視窗裡按滑鼠右鍵，Add Build Target <br>，name打：編譯。Build Target打：all。 <br><br>◎步驟六.編譯。 <br>在剛剛建立的Make Targets "編譯" 上點滑鼠2下，即會開始編譯， <br>此時我們可以發現hello.exe已經產生在我們專案下了。可在底下 <br>C-Build視窗看到以下輸出結果：
<table class=java cellSpacing=1 cellPadding=3 bgColor=#999999 border=0>
    <tbody>
        <tr>
            <td vAlign=top align=left width=1 bgColor=#dddddd>
            <pre><font color=#555555>1<br>2<br></font></pre>
            </td>
            <td vAlign=top align=left bgColor=#ffffff>
            <pre>make -k all
            g++  main.cpp -g -o run
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br><br>◎步驟七. *.exe執行前設定。因為在Windows下Run，所以要先作個設定 <br>，請開啟Project-&gt;Properties-&gt;C/C++ Make Project-&gt;Binary Parser頁面。 <br>Binary Parser下拉式選單，將ELF Parser改成PE Windows Parser。 <br><br>◎步驟八.執行。 <br>Run-&gt;Run as-&gt;C Local Application。 <br>在底下Consloe視窗看到hello.exe的執行結果。 <br><br>註：當原始檔有修改，要重新編譯時，只要滑鼠雙擊我們在步驟五 <br>所建立的Make Targets "編譯"，即可Rebuilding。 
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/120421.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-05-28 12:00 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/05/28/120421.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Splint User’s Manual(zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/05/25/120049.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 25 May 2007 09:59:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/05/25/120049.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/120049.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/05/25/120049.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/120049.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/120049.html</trackback:ping><description><![CDATA[<p class=TextFontCX><a href="http://www.splint.org/manual/html/sec1.html">http://www.splint.org/manual/html/sec1.html</a><br><br><br><br>Splint<a title="" href="http://www.splint.org/manual/html/appNotes.html#_ftn1" name=_ftnref1><span class=MsoFootnoteReference><span class=MsoFootnoteReference><span style="FONT-SIZE: 11pt; FONT-FAMILY: 'Times New Roman'"><u><font color=#0000ff>[1]</font></u></span></span></span></a> is a tool for statically checking C programs for security vulnerabilities and programming mistakes.&nbsp; Splint does many of the traditional lint checks including unused declarations, type inconsistencies, use before definition, unreachable code, ignored return values, execution paths with no return, likely infinite loops, and fall through cases.&nbsp; More powerful checks are made possible by additional information given in source code annotations.&nbsp; Annotations&nbsp;are stylized comments that document assumptions about functions, variables, parameters and types.&nbsp; In addition to the checks specifically enabled by annotations, many of the traditional lint checks are improved by exploiting this additional information.</p>
<p class=TextFontCX>&nbsp;</p>
<p class=TextFontCX>As more effort is put into annotating programs, better checking results. A representational effort-benefit curve for using Splint is shown in Figure 1.&nbsp; Splint is designed to be flexible and allow programmers to select appropriate points on the effort-benefit curve for particular projects.&nbsp; As different checks are turned on and more information is given in code annotations the number of bugs that can be detected increases dramatically.</p>
<p class=TextFontCX>&nbsp;</p>
<p class=beforelist>Problems detected by Splint include:</p>
<p class=TextFontCX style="MARGIN-LEFT: 12.95pt; TEXT-INDENT: -12.95pt"><span style="FONT-FAMILY: Symbol">&#183;<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span> Dereferencing a possibly null pointer (Section 2);</p>
<p class=TextFontCX style="MARGIN-LEFT: 12.95pt; TEXT-INDENT: -12.95pt"><span style="FONT-FAMILY: Symbol">&#183;<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span> Using possibly undefined storage or returning storage that is not properly defined (Section&nbsp;3);</p>
<p class=MsoListBullet><span style="FONT-FAMILY: Symbol">&#183;<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span> Type mismatches, with greater precision and flexibility than provided by C compilers (Section 4.1&#8211;4.2);</p>
<p class=MsoListBullet><span style="FONT-FAMILY: Symbol">&#183;<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span> Violations of information hiding&nbsp;(Section 4.3);</p>
<p class=TextFontCX style="MARGIN-LEFT: 12.95pt; TEXT-INDENT: -12.95pt"><span style="FONT-FAMILY: Symbol">&#183;<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span> Memory management errors including uses of dangling references and memory leaks&nbsp; (Section 5);</p>
<p class=TextFontCX style="MARGIN-LEFT: 12.95pt; TEXT-INDENT: -12.95pt"><span style="FONT-FAMILY: Symbol">&#183;<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span> Dangerous aliasing (Section 6);</p>
<p class=TextFontCX style="MARGIN-LEFT: 12.95pt; TEXT-INDENT: -12.95pt"><span style="FONT-FAMILY: Symbol">&#183;<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span> Modifications and global variable uses that are inconsistent with specified interfaces (Section 7);</p>
<p class=TextFontCX style="MARGIN-LEFT: 12.95pt; TEXT-INDENT: -12.95pt"><span style="FONT-FAMILY: Symbol">&#183;<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span> Problematic control flow such as likely infinite loops (Section 8.3.1), fall through cases or incomplete switches (Section 8.3.2), and suspicious statements (Section 8.4);</p>
<p class=TextFontCX style="MARGIN-LEFT: 12.95pt; TEXT-INDENT: -12.95pt"><span style="FONT-FAMILY: Symbol">&#183;<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span> Buffer overflow vulnerabilities (Section 9);</p>
<p class=TextFontCX style="MARGIN-LEFT: 12.95pt; TEXT-INDENT: -12.95pt"><span style="FONT-FAMILY: Symbol">&#183;<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span> Dangerous macro implementations or invocations (Section 11); and</p>
<p class=TextFontCX style="MARGIN-LEFT: 12.95pt; TEXT-INDENT: -12.95pt"><span style="FONT-FAMILY: Symbol">&#183;<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span> Violations of customized naming conventions.&nbsp; (Section 12).</p>
<p class=TextFontCX>&nbsp;</p>
<p class=MsoCaption>&nbsp;</p>
<center><img height=350 src="http://www.splint.org/manual/html/manual-301_files/image003.gif" width=572> </center><br><br>
<p class=MsoCaption><a name=_Toc534824605></a><a name=_Ref534821281>Figure</a> 1.&nbsp; Typical Effort-Benefit Curve</p>
<p class=TextFontCX>&nbsp;</p>
<p class=TextFontCX>Splint checking can be customized to select what classes of errors are reported using command line flags and stylized comments in the code.&nbsp; In addition, users can define new annotations&nbsp;and associated checks to extend Splint&#8217;s checking or to enforce application specific properties (Section 10).</p>
<p class=TextFontCX><a name=_Ref343085763></a><a name=_Ref343065516>&nbsp;</a></p>
<p class=TextFontCX><strong>About This Document</strong></p>
<p class=TextFontCX>This document is a guide to using Splint.&nbsp; Section 1 explains how to run Splint, interpret messages and control checking.&nbsp; Sections 2&#8211;13 describe particular checks done by Splint.&nbsp; There are some minor dependencies between sections, but in general they can be read in any order.&nbsp; Section 14 covers issues involving libraries and header file inclusion important for running Splint on large systems.</p>
<p class=TextFontCX>&nbsp;</p>
<p class=TextFontCX>This document does not describe technical details of the checking.&nbsp; For technical background and analysis of Splint&#8217;s effectiveness in practice, see the papers available at <a href="http://www.splint.org/"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"><u><font color=#00008b>http://www.splint.org</font></u></span></a>.&nbsp;</p>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/120049.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-05-25 17:59 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/05/25/120049.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>PCLint （zz ）</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/05/24/119598.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Thu, 24 May 2007 02:46:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/05/24/119598.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/119598.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/05/24/119598.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/119598.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/119598.html</trackback:ping><description><![CDATA[<div class=postTitle><a href="http://blog.csdn.net/Tycool/archive/2006/04/14/663765.aspx"><img height=13 src="http://blog.csdn.net/images/authorship.gif" width=15 border=0><u><font color=#0000ff>&nbsp;【原创】VC中多文件工程的PCLint使用详解</font></u></a> </div>
<div class=postText>
<p>2006-4-14 Lander 整理<br>介绍：对于多个源程序文件且多个头文件目录的项目进行PCLint语法检查。</p>
<p>1.安装<br>&nbsp;我使用的是PC.Lint.v8.00e,是不用安装的版本。<br>&nbsp;解开到E:\PC.Lint.v8.00e目录，可执行文件为Lint.exe（lint-nt.exe与其相同，可能为NT平台用的，在Win2000下都可运行)。<br>&nbsp;子目录lnt内是检查的规则及选项文件，这两种文件扩展名全为.lnt。</p>
<p>2.准备自己工程的选项文件<br>&nbsp;在E:\PC.Lint.v8.00e\lnt下新建MyProj.lnt文本文件，我们将自己工程的很多头文件目录，在其中一一列出来，内容如下：<br>&nbsp;<br>&nbsp;std.lnt/*注释：包含的规则和/或选项文件*/<br>&nbsp;env-vc6.lnt<br>&nbsp;/*下面为各头文件目录,可以在字串中不要双引号,可以有多行*/<br>&nbsp;-i"C:\MyProj\IncludeA" -i"C:\MyProj\IncludeB" -iC:\MyProj\IncludeC<br>&nbsp;-iC:\MyProj\IncludeD<br>&nbsp;-e641//另一种注释//这是省略#641错误<br>&nbsp;【注意】指明各头文件目录很重要。头文件各目录的名称可能在VC的Project\Project Settings\Project Options栏中：<br>&nbsp; /I "../Include/PS",可供借鉴(相对路径暂未测试)。<br>&nbsp; 当后面运行Lint时出现无法打开某个头文件时，需要不断添加头文件所在目录的名称到本选项文件中。</p>
<p>3.在VC中运行PCLint（针对单个文件但需包含多个头文件目录）：<br>&nbsp;&nbsp;&nbsp; A 点击Tools/Customize/Tools出现定制窗口<br>&nbsp;&nbsp;&nbsp; B 在Menu contents中双击下面的空白拦，输入拟新增的Tool名称：PCLint<br>&nbsp;&nbsp;&nbsp; C 双击PClint项，在Command中填入要调用的.exe文件名：lint<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Arguments:中填入：-i"E:\PC.Lint.v8.00e\lnt" MyProj.lnt $(FilePath)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 【注意】$(FilePath)这个字串是个宏名，也可以通过点击右边的三角箭头选择;可能为要检查的本文件的路径加文件名，而<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不能是$(FileName)!!!因为它可能只是文件名而不带路径，将导致使用时说无法发现!<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另外,MyProj.lnt这个选项文件必须在$(FilePath)之前。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Initial Directory项：在Arguments项中若缺少-i"E:\PC.Lint.v8.00e\lnt"时将报无法找到各个.lnt文件，可在此<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 栏填E:\PC.Lint.v8.00e\lnt来指定。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 选中"Use Output Window" (这将使PCLint运行的结果在VC下方Output窗口中，双击行号还可以跳到指定行)<br>&nbsp;&nbsp;&nbsp; D 打开一个项目，让焦点位于某个源程序编辑窗口，点击Tools/pclint菜单即可</p>
<p>【注意】直到VC Output窗口中出现Tool returned code: ，才算Tool运行完，若未运行完，可能在再点击PCLint时报错。</p>
<p>4.网上搜到的VC环境多个文件同时Lint的方法，大致为找到各个.c文件，将各文件名经xargs传给lint来实现。但需要find,xargs等<br>命令，似乎需要模拟unix环境的软件支持中才有，我装的Cygwin的环境中对find命令后的格式有问题，无法支持unix中的<br>find . -name *.c,故无法由此找到各个.c文件名。但可以用Cygwin的ls命令来代替find。<br>&nbsp;【原方法如下：】<br>&nbsp; &nbsp;A 点击Tools/Customize/Tools出现定制窗口<br>&nbsp;&nbsp;B 在Menu contents中双击空白拦，输入：PCLint-project<br>&nbsp; C 双击PCLint-project项，在Command:中填入：find<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Arguments:中填入：$(FileDir) -name *.c | xargs pclint -i"c:\unix\usr" -u std.lnt env-vc6.lnt<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 选中"Use Output Window"<br>&nbsp;&nbsp;D 打开一个项目，让焦点位于最项层目前的一个Source Window中，点击Tools/PCLint-project菜单即可</p>
<p>&nbsp;【方法1如下：】<br>&nbsp;&nbsp;A 点击Tools/Customize/Tools出现定制窗口<br>&nbsp;&nbsp;B 在Menu contents中双击空白拦，输入：PCLint-Proj<br>&nbsp;&nbsp;C 双击PCLint-Proj项，在Command:中填入：ls<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Arguments:中填入：*.c |xargs lint -i"E:\PC.Lint.v8.00e\lnt" MyProj.lnt<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Initial Directory项：本栏填写工程的一个源文件子目录(保证在Arguments项中有-i"E:\PC.Lint.v8.00e\lnt")<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 选中"Use Output Window"<br>&nbsp;&nbsp;D 打开一个项目，让焦点位于最顶层目前的一个Source Window中，点击Tools/PCLint-Proj菜单即可</p>
<p>&nbsp;【最简单的方法如下：】<br>&nbsp;&nbsp;A 在MyProj.lnt末尾添加一行 *.c （即目标为本目录下所有.c文件）<br>&nbsp;&nbsp;B 点击Tools/Customize/Tools出现定制窗口<br>&nbsp;&nbsp;C 在Menu contents中双击空白拦，输入：PCLint-Proj<br>&nbsp;&nbsp;D 双击PCLint-Proj项，在Command:中填入：lint<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Arguments:中填入：-i"E:\PC.Lint.v8.00e\lnt" MyProj.lnt<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Initial Directory项：本栏填写工程的一个源文件子目录(保证在Arguments项中有-i"E:\PC.Lint.v8.00e\lnt")<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 选中"Use Output Window"<br>&nbsp;&nbsp;E 打开一个项目，让焦点位于最项层目前的一个Source Window中，点击Tools/PCLint-Proj菜单即可</p>
<p>【注意】上述方法中的ls,xargs等命令位于Cygwin的目录中，需要将路径添加到系统的PATH中：<br>&nbsp; "我的电脑"(右击鼠标)-&gt;"属性"-&gt;"高级"-&gt;"环境变量"-&gt;"系统变量"-&gt;"Path"<br>&nbsp;&nbsp;&nbsp; 加入"C:\cygwin\bin"重启生效。<br>&nbsp;ls *.c将同时找到.c文件和.cpp文件，但是也会将非工程所需的.c文件编译进来，需要手工把文件转走。<br>&nbsp;另外，这种方法一次只能Lint一个目录，每完成一个目录就要重新设置Initial Directory项为新的要检查的目录。</p>
<p>5.在DOS窗口中对一个目录多个文件进行Lint<br>1)基于Cygwin<br>cd C:\MyProj\SrcA\<br>ls *.c | xargs lint -i"E:\PC.Lint.v8.00e\lnt" MyProj.lnt &gt;&gt; LintOutput.txt<br>【注意】ls *.c 也可以用DOS命令dir *.c/B来替换，/B的意思是仅列出各文件名。&gt;&gt;LintOutput.txt的意思是将Lint结果输出到<br>LintOutput.txt文件中。<br>2)无Cygwin支持<br>cd C:\MyProj\SrcA\<br>dir *.c /B<br>将所有列出的.c文件名称复制到E:\PC.Lint.v8.00e\lnt\MyProj.lnt中，内容如下：<br>&nbsp;std.lnt/*注释：包含的规则和/或选项文件*/<br>&nbsp;env-vc6.lnt<br>&nbsp;/*下面为各头文件目录,可以在字串中不要双引号,可以有多行*/<br>&nbsp;-i"C:\MyProj\IncludeA" -i"C:\MyProj\IncludeB" -iC:\MyProj\IncludeC<br>&nbsp;-iC:\MyProj\IncludeD<br>&nbsp;-e641//另一种注释//这是省略#641错误<br>&nbsp;a.c //指定要Lint的文件<br>&nbsp;b.c<br>&nbsp;c.c<br>&nbsp;最后几行指定的要Lint之文件也可以用通配符，如：<br>&nbsp;*.c<br>然后直接运行 lint -i"E:\PC.Lint.v8.00e\lnt" MyProj.lnt &gt;&gt; LintOutput.txt</p>
</div>
<br><br><br><br>===================================<br>
<div id=art style="MARGIN: 15px" width="100%">
<p>LINT工具是一种软件质量保证工具，许多国外的大型专业软件公司，如微软公司，都&nbsp; <br>把它作为程序检查工具，在程序合入正试版本或交付测试之前一定要保证通过了LINT检查&nbsp; <br>，他们要求软件工程师在使用LINT时要打开所有的编译开关，如果一定要关闭某些开关，&nbsp; <br>那么要给出关闭这些开关的正当理由。&nbsp; <br><br>　　可想而知，如果从我们编码后第一次编译程序时就使用LINT来检查程序，并且保证消&nbsp; <br>除所有的LINT告警，我们就不会遇到象今天这么多的告警信息。即使在今天，我们如果能&nbsp; <br>抽出一定的精力来消除程序中的LINT告警，以后再维持这种无告警状态就是很容易的了。&nbsp; <br>我们程序质量的提高也是不言而喻的。&nbsp; <br><br>　　PC-LINT是GIMPEL&nbsp;SOFTWARE公司的产品，其中的内容是非常广泛的，光是选项就有30&nbsp; <br>0多个，涉及到程序编译及语法使用中的方方面面。本篇培训材料旨在引导读者入门，学会&nbsp; <br>PC-LINT的基本使用方法，起抛砖引玉的作用，能让读者从这里起步继续去研究如何娴熟地&nbsp; <br>使用PC-LINT的各种选项，能让它充分为我们的开发工作服务。&nbsp; <br><br>1.概述&nbsp; <br>　　如果要给LINT工具下一个形象点的定义，那就是：一种更加严格的编译器。它不仅可&nbsp; <br>以象普通编译器那样检查出一般的语法错误，还可以检查出那些虽然完全合乎语法要求，&nbsp; <br>但很可能是潜在的、不易发现的错误。请看下面的例子：&nbsp; <br>1：&nbsp; <br>2：char&nbsp;*report(&nbsp;int&nbsp;m,&nbsp;int&nbsp;n,&nbsp;char&nbsp;*p&nbsp;)&nbsp; <br>3：{&nbsp; <br>4：&nbsp;int&nbsp;result;&nbsp; <br>5：&nbsp;char&nbsp;*temp;&nbsp; <br>6：&nbsp;long&nbsp;nm;&nbsp; <br>7：&nbsp;int&nbsp;i,&nbsp;k,&nbsp;kk;&nbsp; <br>8：&nbsp;char&nbsp;name[11]&nbsp;=&nbsp;"Joe&nbsp;Jakeson";&nbsp; <br>9：&nbsp; <br>10：&nbsp;nm&nbsp;=&nbsp;n&nbsp;*&nbsp;m;&nbsp; <br>11：&nbsp;temp&nbsp;=&nbsp;p&nbsp;==&nbsp;""&nbsp;?&nbsp;"null"&nbsp;:&nbsp;p;&nbsp; <br>12：&nbsp;for(&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;13：&nbsp;{&nbsp; <br>14：&nbsp;k++;&nbsp; <br>15：&nbsp;kk&nbsp;=&nbsp;i;&nbsp; <br>16：&nbsp;}&nbsp; <br>17：&nbsp; <br>18：&nbsp;if(&nbsp;k==&nbsp;1&nbsp;)&nbsp;result&nbsp;=&nbsp;nm;&nbsp; <br>19：&nbsp;else&nbsp;if(&nbsp;kk&nbsp;&gt;&nbsp;0&nbsp;)&nbsp;result&nbsp;=&nbsp;1;&nbsp; <br>20：&nbsp;else&nbsp;if(&nbsp;kk&nbsp;&lt;&nbsp;0&nbsp;)&nbsp;result&nbsp;=&nbsp;-1;&nbsp; <br>21：&nbsp; <br>22：&nbsp;if(&nbsp;m&nbsp;==&nbsp;result&nbsp;)&nbsp;return(&nbsp;temp&nbsp;);&nbsp; <br>23：&nbsp;else&nbsp;return(&nbsp;name&nbsp;);&nbsp; <br>24：}&nbsp; <br>　　上面的代码用一般的编译器编译是一段有效的代码，但是用PC-LINT编译就会有几个告&nbsp; <br>警。首先第8行向name数组赋值时丢掉了nul字符，第10行的乘法精度会失准，第11行的比&nbsp; <br>较有问题，第14行的变量k没有初始化，第15行的kk可能没有被初始化，第22行的result也&nbsp; <br>有可能没有被初始化，第23行返回的是一个局部对象的地址。这段代码在大部分编译器下&nbsp; <br>是可以顺利编译通过的，继续查找其中的错误就要靠人工调试程序，如果程序很大，这将&nbsp; <br>是一项烦琐的工作，没有人可以保证能找出所有的这类问题，但PC-LINT只通过一次简单的&nbsp; <br>编译就可做到，显然为我们节省了大量的开发时间。&nbsp; <br><br>　　下面就让我们看看如何安装使用PC-LINT。&nbsp; <br>2.如何安装PC-LINT&nbsp; <br>　　PC-LINT的软件的安装过程比较复杂，选项较多，下面根据安装过程，逐条说明每一步&nbsp; <br>的含义。&nbsp; <br>0）如果是zip文件，将ZIP安装文件展开到目录C:\lint.ins下，进入COMMAND&nbsp;PROMPT，先&nbsp; <br>进行目录映射&nbsp;subst&nbsp;g:&nbsp;c:\lint.ins，然后转到G:&nbsp;,&nbsp;执行install。其他步骤和下面的从&nbsp; <br>软盘安装是一样的。&nbsp; <br><br>1）在A:驱插入PC-LINT安装盘，输入A:\&gt;install命令，进入开始安装栏，按任意键继续，&nbsp; <br>进入PC-LINT介绍栏，再按任意键继续。&nbsp; <br>2）进入环境选择栏，这一栏中有三个选项：&nbsp; <br>Windows&nbsp;NT/Windows&nbsp;95&nbsp; <br>MS-DOS（DOS&nbsp;extended）&nbsp; <br>OS/2（32bit）&nbsp; <br>如果计算机安装了WIN95、WIN97、WIN98或WINNT要选择Windows&nbsp;NT/Windows&nbsp;95，如果&nbsp; <br>只有DOS则选择DOS。&nbsp; <br>3）进入安装目录选择栏，它推荐的是C:\&gt;LINT，如不想安装在这个目录下，可输入自己想&nbsp; <br>要安装的目录，然后按回车确认，如果要安装的目录不存在，它会提示为你建立这个目录&nbsp; <br>。我们这里选C:\&gt;LINT&nbsp; <br>4）选择安装盘所在的磁盘驱动器，我们这里选A:&nbsp; <br>5）判断是否要选择多种编译器或编译库的配置，如果要对不同编译环境下的程序进行L&nbsp; <br><br>INT，则选YES，否则选NO。然后回车确认。&nbsp; <br>6）这时看到一个编译器列表，在这个表中选择自己使用的编译器，如果表中没有自己使用&nbsp; <br>的编译器，可选择通用编译器：Generic&nbsp;Compilers。按回车确认。这个选项会体现在co-&nbsp; <br>xxx.lnt文件中。&nbsp; <br>7）接着安装程序会让你选择一个的内存模型，可以根据自己程序区和数据区的实际大小选&nbsp; <br>择一个恰当的内存模型。如果CPU为32位68K系列，则要选择：32-bit&nbsp;Flat&nbsp;Module。&nbsp; <br>内存模型的选项会体现在STD.LNT文件中。&nbsp; <br>8）选完内存模型后，会看到一个库类型的列表，在这里选择一个或多个编译时使用的库。&nbsp; <br>这个选项会体现在LIB-xxx.LNT文件中。&nbsp; <br>9）接着是让你选择为使用C++编程提出过重要建议的作者，选择的某作者后，他提出的编&nbsp; <br>程建议方面的选项将被打开。与作者选择有关的选项会体现在AU-xxx.LNT文件中。&nbsp; <br>10）下一步是设置包含文件目录。有两种选项，第一种是使用环境变量INCLUDE，环境变量&nbsp; <br>在批处理文件中设置，环境变量后每个目录用分号隔开，例如可设成&#8220;INCLUDE=C:\MRI\M&nbsp; <br>CC68K;D:\LAP\SRC\INC&#8221;。第二种选项是使用-i选项，-i选项体现在STD.LNT文件中，每个&nbsp; <br>目录前以-I引导，目录间以空格分隔，例如可设成&#8220;-IC:\MRI\MCC68K&nbsp;-ID:\LAP\SRC\INC&nbsp; <br>&#8221;。如果选择使用-I选项，安装程序会接着让你输入包含文件所在的目录。&nbsp; <br>11）&nbsp;如果前面选择了使用多个编译环境，这里将会问你是否选择更多的编译环境，如果选&nbsp; <br>YES，将会从第6步开使重复。如果选NO则会结束编译器选择。&nbsp; <br>12）接下来将会准备产生一个&nbsp;反映全局编译信息显示情况的选项文件OPTIONS.LNT，该文&nbsp; <br>件的产生方式有两种，一种是安装程序对几个核心选项逐一解释并提问你是否取消该选项&nbsp; <br>，如果你选择取消，则会体现在OPTIONS.LNT文件中，具体体现方式是在该类信息编码前加&nbsp; <br>-e，后面第13~18步是逐一选择核心选项的过程。如果选择第二种选择方式，安装文件会先&nbsp; <br>生成一个空的OPTIONS.LNT文件，等你以后在实际应用时加入必要的选项。&nbsp; <br>13）是否关闭赋值时的布尔测试告警，如：if(a=f()){...&nbsp; <br>14）是否关闭赋值时的有符号量和无符号量间的不匹配告警，通常情况下，这种赋值不会&nbsp; <br>带来问题，选择关闭该告警信息的同时，其他类型的有符号量和无符号量间混合操作的告&nbsp; <br>警仍然是打开的。&nbsp; <br>15）当把一个整形量赋值给一个比它短的量时，后者会丢失精度，例如把一个INT量赋值给&nbsp; <br>给一个CHAR量。本步是让你选择是否关闭该类告警。&nbsp; <br>16）是否关闭左移带符号量的告警。通常PC-LINT会对所有带符号量的移动产生告警，但右&nbsp; <br>移一般是由不同的CPU来确定是否将符号位移入，左移一般是不会产生什么问题的，所以可&nbsp; <br>以选择关闭该告警。&nbsp; <br>17）在一个C函数被定义或声明前调用它，并不总是会产生错误，在这里可以选择是否关闭&nbsp; <br>该告警选项。该选项对C++程序不起作用。&nbsp; <br>18）是否关闭&#8220;调用不存在的函数原型&#8221;告警。有些程序员不愿遵守严格的函数原形定义&nbsp; <br>约定，但PC-LINT会在调用一个没有定义的函数原型时产生一个告警，在这里可以选择关闭&nbsp; <br>该告警。&nbsp; <br>19）通过上面的步骤确定OPTIONS.LNT文件的形式后，接着是选择编译环境。PC-LINT提供&nbsp; <br>了集成在多种开发环境中工作的功能，例如可集成在VC、BC、Source&nbsp;Insight中。假如我&nbsp; <br>们在这里选择Source&nbsp;Insight。选择后安装程序会继续问你是否还选择其它的环境，可根&nbsp; <br>据自己应用的实际情况选择一种或多种开发环境。开发环境的选择情况记录在env-xxx.ln&nbsp; <br>t文件中。&nbsp; <br>20）安装程序会生成一个LIN.BAT文件，该文件是运行PC-LINT的批处理文件，为了使该文&nbsp; <br>件能在任何路径下运行，安装程序提供了两种方法供你选择。第一种方法是让你选择把LI&nbsp; <br>N.BAT拷贝到任何一个PATH目录下，在安装结束运行LCOPY.BAT文件时，会把LIN.BAT拷贝到&nbsp; <br>你指定的目录。第二种方法是生成一个LSET.BAT文件，在每次使用PC-LINT前先运行它来设&nbsp; <br>置路径，或者把LSET.BAT文件的内容拷贝到AUTOEXEC.BAT文件中。&nbsp; <br>21）在安装程序执行完后第一件事是在你安装的目录下执行LCOPY.BAT文件。它会从安装盘&nbsp; <br>拷贝将一些文件拷贝到安装目录下，并根据你在安装过程中的选择来设置文件中的参数。&nbsp; <br><br>3.LINT&nbsp;一个C文件&nbsp; <br>3.1用命令行方式进行LINT&nbsp; <br>如果使用LIN.BAT批处理文件进行LINT，在LINT前要先看一下该批处理文件中的内容，里面&nbsp; <br>包含了LINT-NT命令和命令选项，可以根据自己的要求来修改、增减选项。我们看到，在这&nbsp; <br>个批命令中嵌套了一个std.lnt文件，在std.lnt文件中还嵌套了co.lnt、options.lnt和l&nbsp; <br>ib-stl.lnt文件，原则上*.lnt文件是可以无限制嵌套，该类文件中一般都是了LINT的选项&nbsp; <br>，可通过修改这些文件来修改LINT选项，选项是按照从左到右的顺序执行的。可执行下面&nbsp; <br>命令行：&nbsp; <br>C:\abc\src&gt;lin&nbsp;alpha.c&nbsp;beta.c&nbsp;gamma.c&nbsp; <br>通常对于由多个C模块组成的程序，最好先分别对每个C模块单元进行LINT检查，做单元LI&nbsp; <br>NT时可如下运行：&nbsp; <br>C:\abs\src&gt;lin&nbsp;-u&nbsp;alpha.c&nbsp; <br>其中-u是单元选项，使用-u后可以关闭一些检查多模块时会产生的告警，例如&#8220;函数未被&nbsp; <br>使用&#8221;或&#8220;函数没有定义&#8221;等。&nbsp; <br>也可以不使用LIN.BAT批处理文件，而直接使用LINT命令。在DOS环境下LINT命令为LINT.E&nbsp; <br>XE，在Windows95/NT环境下为LINT-NT.EXE，在OS2环境下为LINT-OS2.EXE。直接使用LINT&nbsp; <br>命令要注意的一点是要在使用前预先设置LINT目录所在路径，最好的方法是把该路径加在&nbsp; <br>AUTOEXEC.BAT文件中。其它的使用方法与使用批处理文件相同。例如：&nbsp; <br>C:\abs\src&gt;lint-nt&nbsp;-ic:\lint\&nbsp;std.lnt&nbsp;-os(_lint.tmp)&nbsp;*.c&nbsp; <br>3.2用开发环境进行LINT&nbsp; <br>也可以使用开发环境来执行LINT操作，一般开发环境都支持运行可执行文件，但不一定支&nbsp; <br>持运行批处理文件，下面用Source&nbsp;Insight&nbsp;,&nbsp;Ultra&nbsp;Edit,&nbsp;MSVC&nbsp;6.0&nbsp;来举例说明如何在&nbsp; <br>开发环境下进行LINT。&nbsp; <br>3.2.1&nbsp;在Source&nbsp;Insight中集成&nbsp; <br>如果你在安装过程中选定了使用某个开发环境，安装程序会在你安装的目录下生成一个en&nbsp; <br>v-xxx.lnt的文件，例如选择了Source&nbsp;Insight就会有一个env-si.lnt文件。用编辑器打开&nbsp; <br>该文件，在该文件开始的注释中说明了如何将PC-LINT功能集成在开发环境中，集成在Sou&nbsp; <br>rce&nbsp;Insight中的过程如下：&nbsp; <br>1）从Options菜单中选择&#8220;Custom&nbsp;Commands&#8221;命令项。&nbsp; <br>2）在Name栏中输入&#8220;PC-lint&nbsp;&#8221;，原则上这个名称可以随便起，只要你能搞清楚它的含义&nbsp; <br>就可以了。&nbsp; <br>3）在Run栏中输入&#8220;c:\lint\lint-nt&nbsp;-u&nbsp;-ic:\lint&nbsp;std&nbsp;env-si&nbsp;%f&#8221;其中c:\lint是你P&nbsp; <br>C-LINT的安装目录。&nbsp; <br>4）在Output栏中选择&#8220;Iconic&nbsp;Window&#8221;、&#8220;Capture&nbsp;Output&#8221;。&nbsp; <br>5）在Control栏中选择&#8220;Save&nbsp;Files&nbsp;First&#8221;。&nbsp; <br>6）在Source&nbsp;Links&nbsp;in&nbsp;Output栏中选择&#8220;Parse&nbsp;Links&nbsp;in&nbsp;Output&#8221;、&#8220;File，then&nbsp;Lin&nbsp; <br>e&#8221;。&nbsp; <br>7）在Pattern栏中输入&#8220;^\([^&nbsp;]*\)&nbsp;\([0-9]+\)&#8221;。&nbsp; <br>8）点Add键加入该命令。如下图：&nbsp; <br>9）使用时，在Source&nbsp;Insight下打开要LINT的文件，打开Options菜单中的&#8220;Custom&nbsp;Com&nbsp; <br>mands&#8221;命令项，在&#8220;Command&#8221;栏中选择&#8220;PC-lint&nbsp;unit&nbsp;check&#8221;命令运行即可。&nbsp; <br>注意到我的Run一栏的参数和上面的提示不一样，其实我的其他古怪参数都放到c:\lint\s&nbsp; <br>td.lnt中了。请注意，不论你怎样配置参数一定不要忘记了将si-env.lnt包含在你的配置&nbsp; <br>文件里，否则就无法进行错误信息和程序的自动对应了。&nbsp; <br>为了使用方便，你还可以配置一下Menu按钮，将它加到系统菜0单里，这属于一般性的&nbsp; <br>Source&nbsp;Insight应用，笔者就不在此赘述了。&nbsp; <br>第二笔者在NT中使用Source&nbsp;Insight时，好象集成不了，原因暂时不明了。上面的例子在&nbsp; <br>WIN&nbsp;95下测试成功。&nbsp; <br>如果要修改LINT选项，可直接在Run栏中修改，也可专门编辑一个*.lnt文件放在c:\lint目&nbsp; <br>录下，并将该文件名加入Run栏中，和命令行方式是一样的。&nbsp; <br>3.2.2在Ultra&nbsp;Editor中集成&nbsp; <br>选取&nbsp;Menu&nbsp;|&nbsp;Advanced&nbsp;|&nbsp;Tool&nbsp;Configuration&nbsp;...&nbsp;，&nbsp;显示如下图：&nbsp; <br>1）点按&#8220;Insert",&nbsp; <br>2）在command&nbsp;line:中填写：c:\lint\lint-nt&nbsp;c:\lint\std.lnt&nbsp;%f&nbsp; <br>3）在Menu&nbsp;Item中填写：PC-LINT&nbsp; <br>4）在Command&nbsp;Output中选择：&nbsp;(x)&nbsp;Output&nbsp;to&nbsp;List&nbsp;Box&nbsp;和&nbsp;(x)&nbsp;Capture&nbsp;Output&nbsp; <br>5）点按"OK"&nbsp; <br>如图所示的配置笔者在UE6.0&nbsp;/&nbsp;NT&nbsp;4.0&nbsp;下测试成功。&nbsp; <br>3.2.3&nbsp;在MSVC&nbsp;6.0中集成&nbsp;
<p>//这个好使过<br>基本原理是一样的：&nbsp; <br>1）选取&nbsp;menu&nbsp;|&nbsp;tools&nbsp;|&nbsp;customize.....&nbsp; <br>2）选取&nbsp;Tools&nbsp;Tab:&nbsp; <br>3）点按主对话框上方的虚线小方框&nbsp;New&nbsp;a&nbsp;tool&nbsp;item&nbsp; <br>4）输入&nbsp;name:&nbsp;PC-LINT&nbsp; <br>5）输入&nbsp;Command:&nbsp;c:\lint\lint-nt.exe&nbsp; <br>6）输入&nbsp;Arguments:&nbsp;c:\lint\std.lnt&nbsp;$(FilePath)&nbsp; //注：替std.lnt为lnt\env-vc6.lnt<br>7)&nbsp;选择&nbsp;(x)&nbsp;Use&nbsp;Output&nbsp;Window&nbsp; <br>8）Close&nbsp; <br>完成后，在tools菜单下就会有一项PC-LINT选项。&nbsp; <br>下面是笔者在VC6&nbsp;/&nbsp;Win&nbsp;NT&nbsp;4.0&nbsp;的情况下的TOOL配置图：&nbsp; <br>3.3LINT选项&nbsp; <br>LINT选项可以放在注释中，例如：&nbsp; <br>/*lint&nbsp;option1&nbsp;option2&nbsp;...&nbsp;optional&nbsp;commentary&nbsp;*/&nbsp; <br>//lint&nbsp;option1&nbsp;option2&nbsp;...&nbsp;optional&nbsp;commentary&nbsp; <br>选项间要以空格分开，lint命令一定要小写，并且紧跟在/*或//后面，不能有空格。如果&nbsp; <br>选项由类似于操作符和操作数的部分组成，例如-esym(534,&nbsp;printf,&nbsp;scanf,&nbsp;operat　or&nbsp; <br>new)，其中最后一个选项是operator&nbsp;new，那么在operator和new中间只能有一个空&nbsp; <br>格。&nbsp; <br>选项还可以放在宏定义中，例如：&nbsp; <br>#define&nbsp;DIVZERO(x)&nbsp;/*lint&nbsp;-save&nbsp;-e54&nbsp;*/&nbsp;((x)&nbsp;/o)&nbsp;/*lint&nbsp;-restore&nbsp;*/&nbsp; <br>LINT的选项很多共有300多种，大体可分为以下几类：&nbsp; <br>1）错误信息禁止选项&nbsp; <br>该类选项是用于禁止生成某类错误信息的选项，最常用的是-e和+e，-e是禁止生成某类错&nbsp; <br>误信息，+e是恢复生成某类错误信息。运行lint目录下的msg.exe可以得到msg.txt文件，&nbsp; <br>这个长达5000行的文件包含了所有的错误信息号和解释。&nbsp; <br>-w&nbsp;对于所有大于级别的告警信息都不显示。&nbsp; <br>-wlib()对于所有大于级别的关于库函数数的告警信息都不显示。我们可以用-wlib(0)来屏&nbsp; <br>蔽所有的库函数的告警信息，-wlib(1)只显示库函数中的句法错误。&nbsp; <br>-esym(#,)&nbsp;可以屏蔽对于特定符号的某告警信息。&nbsp; <br>2）变量类型大小选项&nbsp; <br>不同的目标机、编译系统变量类型的的大小（如短整形变量、整形变量等）会有所不同，&nbsp; <br>该类选项用于为目标机设置变量类型的大小。由于默认的设置与大部分的编译器是匹配的&nbsp; <br>，这些专门的设置通常情况下是不需要的，只在特别的目标机结构中才用。例如一个M680&nbsp; <br>00目标机，它的int类型和指针类型通常是32bit的，这时你应该使用选项：-si4&nbsp; <br>-sp4。这些尺寸参数的当前值可以通过help屏来获得，例如可以输入以下命令行：&nbsp; <br>lin&nbsp;-si4&nbsp;-sp4&nbsp;？&nbsp; <br>3）冗长信息选项&nbsp; <br>冗长信息指的是LINT过程中产生的一些与编译过程有关的信息，而不是真正的告警信息、&nbsp; <br>错误信息等。是否生成这些信息可以通过-v和+v选项来决定。+v是生成这些信息，-v是关&nbsp; <br>闭这些信息，这组选项中除+v外，其它所有选项都可以关闭+v选项。&nbsp; <br>4）标记选项&nbsp; <br>以+f、++f、-f和--f开头的选项是标记选项。他们的逻辑含义分别如下：&nbsp; <br>+f...：通过把标志置为1而把它置为ON&nbsp; <br>-f...：通过把标志置为0而把它置为OFF&nbsp; <br>++f...：标志增1&nbsp; <br>--f...：标志减1&nbsp; <br>后面两个用于你想在局部把一个标志置为ON的情况，而不影响全局设置。例如你可以这样&nbsp; <br>使用：&nbsp; <br>/*lint&nbsp;++flb&nbsp;*/&nbsp; <br>int&nbsp;printf(&nbsp;);&nbsp; <br>/*lint&nbsp;--flb&nbsp;*/&nbsp; <br>标记选项的种类很多，基本含义是用于打开或关闭某类语法情况使用，例如允许使用缩写&nbsp; <br>结构体名称，允许使用无名联合体，把所有模块当作C++编译等。&nbsp; <br>5）消息显示选项&nbsp; <br>消息显示选项用于定义消息输出格式。主要有消息高度选项、消息宽度选项、消息格式选&nbsp; <br>项等。&nbsp; <br>6）其它选项&nbsp; <br>其它选项中的种类很多，各种类间差异很大，在这里就不一一介绍了，建议大家看一看《&nbsp; <br>PC-LINT》一书，第五章有对每种选项的详细说明。lint本身也有一些说明信息，&nbsp;lint-n&nbsp; <br>t&nbsp;2&gt;&nbsp;lint.txt&nbsp;然后狂按几个回车就可以生成一个lint选项的说明文件。&nbsp; <br>4.LINT一个工程下的多个C文件&nbsp; <br>4.1为何要LINT多个C文件&nbsp; <br>在程序编码初期，我们关心的可能只是单个C模块种中的语法问题，等到编程后期，对于由&nbsp; <br>多个C模块组成的程序，我们希望了解当把多个模块连接在一起后是否还有存在于模块间的&nbsp; <br>语法问题。这时编译器虽然能给出一些告警，但PC-LINT的连接能给出更多的告警。还有当&nbsp; <br>我们能保证其中的几个模块相对稳定，而另外几个模块仍有问题时可以先将几个稳定的模&nbsp; <br>块编译连接成一个目标文件，文件每次修改完成后先单独编译，然后连接入总的目标文件&nbsp; <br>。&nbsp; <br>4.2如何LINT一个工程下的多个C文件&nbsp; <br>象我们平时使用的编译工具一样，PC-LINT在编译连接多个C文件时也会先把每个C文件编译&nbsp; <br>生成中间的目标文件*.lob，然后再将所有的LOB文件连接在一起。LOB是Lint&nbsp;Object&nbsp;Mod&nbsp; <br>ule的缩写。这个文件中包含了一个C或C++模块的所有外部信息。生成LOB文件时有三种选&nbsp; <br>项要注意：第一种是-u，如果要LINT生成LOB文件，就一定要加-u选项；第二种是-zero或&nbsp; <br>-zero(500)选项，为了保证LOB文件在模块存在错误的情况下也能生成，就一定要加这个选&nbsp; <br>项；第三种是-oo[(filename)]，filename是生成的LOB文件的名称，在-oo后面，可加，也&nbsp; <br>可不加，如不加，则LOB文件名与原C模块的名称相同，例如：&nbsp; <br>lint&nbsp;-u&nbsp;alpha.c&nbsp;-oo(a1)&nbsp; <br>生成的LOB文件名为：a1.lob&nbsp; <br>lint&nbsp;-u&nbsp;alpha.c&nbsp;-oo&nbsp; <br>生成的LOB文件名为：alpha.lob&nbsp; <br>LINT一个工程下的多个C模块，在用户的源程序目录下一般需要三个文件：&nbsp;一个选项文件&nbsp; <br>（*.lnt）、一个批处理文件（*.bat）和一个MAKEFILE文件（*.mak）。下面一一讲述如何&nbsp; <br>制作这些文件。&nbsp; <br>1）选项文件（*.lnt）&nbsp; <br>选项文件在前面也提到过，你可以把你LINT每个C文件时时用到的所有公共选项罗列在该文&nbsp; <br>件中，选项生效的顺序按照从左到右，从上到下的原则。该类文件可以层层嵌套，嵌套的&nbsp; <br>层数没有限制。例如make.lnt文件：&nbsp; <br>-iC:\lint&nbsp; <br>std.lnt&nbsp; <br>+os(temp)&nbsp; <br>-e46&nbsp; <br>+vm&nbsp; <br>-zero&nbsp; <br>2）批处理文件（*.bat）&nbsp; <br>制作批处理文件时要注意要在该文件中调用TCMAKE.EXE文件和MAKEFILE文件，例如lintma&nbsp; <br>ke.mak文件：&nbsp; <br>@echo&nbsp;Lint&nbsp;Making&nbsp;'makelap':&nbsp; <br>tcmake&nbsp;-flintmake.mak&nbsp; <br>@echo&nbsp;End&nbsp;of&nbsp;making&nbsp; <br>3）MAKEFILE文件（*.mak）&nbsp; <br>MAKEFILE使用的TCMAKE的语法，和我们平时开发编译时使用的MAKEFILE文件语法格式一样&nbsp; <br>，例如下面的lintmake.mak文件：&nbsp; <br>MCCPATH&nbsp;=&nbsp;c:\mcc68k&nbsp; <br>OPTION&nbsp;=&nbsp;-u&nbsp;make.lnt&nbsp;-oo&nbsp; <br>GLOBLE&nbsp;=&nbsp;os.h&nbsp;l2lap.h&nbsp; <br>mail_depend&nbsp;=&nbsp;$(GLOBLE)&nbsp;q931.h&nbsp;mail.h&nbsp; <br>lapmain_depend&nbsp;=&nbsp;$(GLOBLE)&nbsp;l1pubdef.h&nbsp;q931.h&nbsp;mail.h&nbsp; <br>lapos_depend&nbsp;=&nbsp;$(GLOBLE)&nbsp; <br>fhdlc1_depend&nbsp;=&nbsp;$(GLOBLE)&nbsp;cpuhdlc.h&nbsp;bd_prar.h&nbsp;q931.h&nbsp; <br>OBJ&nbsp;=&nbsp;mail.lob&nbsp;lapmain.lob&nbsp;lapos.lob&nbsp;fhdlc1.lob&nbsp; <br>project.lob&nbsp;:&nbsp;$(OBJ)&nbsp; <br>lint-nt&nbsp;make.lnt&nbsp;-e768&nbsp;-e769&nbsp;*.lob&nbsp; <br>mail.lob:&nbsp;mail.c&nbsp;$(mail_depend)&nbsp; <br>lint-nt&nbsp;$(OPTION)&nbsp;mail.c&nbsp; <br>lapmain.lob:&nbsp;lapmain.c&nbsp;$(lapmain_depend)&nbsp; <br>lint-nt&nbsp;$(OPTION)&nbsp;lapmain.c&nbsp; <br>lapos.lob:&nbsp;lapos.c&nbsp;$(lapos_depend)&nbsp; <br>lint-nt&nbsp;$(OPTION)&nbsp;lapos.c&nbsp; <br>fhdlc1.lob:&nbsp;fhdlc1.c&nbsp;$(fhdlc1_depend)&nbsp; <br>lint-nt&nbsp;$(OPTION)&nbsp;fhdlc1.c&nbsp; <br>4.3简单的LINT多个文件&nbsp; <br>假设我们的工程不复杂，我们可以负担起每次都将所有的文件都lint一遍的开销，也可以&nbsp; <br>不使用上面的正规用法。笔者在实践中发现，将所有的*.c文件放在一个lint命令中，同样&nbsp; <br>能完成lint整个工程的目的。&nbsp; <br>如：&nbsp; <br>lint-nt&nbsp;c:\lint\std.lnt&nbsp;AllMySource.lnt&nbsp; <br>在AllMySource.lnt中包括你的工程中的所有源文件：&nbsp; <br>a1.c&nbsp; <br>a2.c&nbsp; <br>a3.c&nbsp; <br>需要注意的是，在std.lnt文件中就不需要-u选项了。因为我们已经提供了所有的信息&nbsp; <br></p>
<div></div>
</div>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/119598.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-05-24 10:46 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/05/24/119598.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[C++]static全局变量/全局变量，static函数/普通函数，函数中static变量/函数中的变量，类中的static成员变量/普通类成员变量  (zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/05/22/119155.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Tue, 22 May 2007 08:32:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/05/22/119155.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/119155.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/05/22/119155.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/119155.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/119155.html</trackback:ping><description><![CDATA[<p><a href="http://blog.csdn.net/duckur/archive/2005/11/05/523545.aspx">http://blog.csdn.net/duckur/archive/2005/11/05/523545.aspx</a><br><br><br><br>static Global variable: 文件作用域：只在声明的文件中有效，其他源文件中不可见；同时有了static的生命周期<br>Global variable:文件作用域：可以加上extern 声明为外部变量，跨文件作用域</p>
<p>static (Global) Function: 有文件作用域，只在本文件中使用<br>Global Function:无文件作用域</p>
<p>static Member (in Function) variable:函数调用完成后，变量保存状态，再次调用函数，不会重新分配空间<br>Member(in Funcition) variable:函数内的生命周期</p>
<p>static Member(in Class) variable: 属于类范围，<br>Member(in Class) variable:属于类派生的特定对象，生命周期和对象一致</p>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/119155.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-05-22 16:32 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/05/22/119155.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c/c++ file template</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/05/22/119105.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Tue, 22 May 2007 05:23:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/05/22/119105.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/119105.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/05/22/119105.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/119105.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/119105.html</trackback:ping><description><![CDATA[<p><a href="http://bigwhite.blogbus.com/archives/1021158.html">http://bigwhite.blogbus.com/archives/1021158.html</a><br><br><br>//in ANSI_C_CODING_STANDARDS.h</p>
<p>/*<br>&nbsp;* Copyright 2005, XX, Inc., China<br>&nbsp;* All rights reserved. <br>&nbsp;*<br>&nbsp;* XX's source code is an unpublished work and the use of a copyright notice does <br>&nbsp;* not imply otherwise. This source code contains confidential, trade secret material of <br>&nbsp;* XX, Inc. Any attempt or participation in deciphering, decoding, reverse engineering<br>&nbsp;* or in any way altering the source code is strictly prohibited, unless the prior written <br>&nbsp;* consent of XX, Inc. is obtained.<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* @file ANSI_C_CODING_STANDARDS.h<br>&nbsp;* @author tony_bai<br>&nbsp;* @date 2005-07-01<br>&nbsp;* @brief the template for ANSI C<br>&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; header file<br>&nbsp;*/</p>
<p>/* <br>&nbsp;* @revision<br>&nbsp;*&nbsp;&nbsp; @version 0.1<br>&nbsp;*&nbsp;&nbsp; @date 2005-08-01<br>&nbsp;*&nbsp;&nbsp; @Revisor tony_bai<br>&nbsp;*&nbsp;&nbsp; <br>&nbsp;* @revision<br>&nbsp;*&nbsp;&nbsp; @version 0.2<br>&nbsp;*&nbsp;&nbsp; @date 2005-09-01<br>&nbsp;*&nbsp;&nbsp; @Revisor tony_bai<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* @glossary<br>&nbsp;*&nbsp;&nbsp; xx - xxxxx<br>&nbsp;*&nbsp;&nbsp; xx - xxxxx<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* @usage<br>&nbsp;*<br>&nbsp;*/</p>
<p>#ifndef ANSI_C_CODING_STANDARDS_H<br>#define ANSI_C_CODING_STANDARDS_H</p>
<p>#include &lt;ANSI C Standard Library Header File&gt;<br>#include &lt;Operating System Library Header File&gt; <br>#include "Your System Library Header File"</p>
<p>/*<br>&nbsp;* ####################<br>&nbsp;* # global constants #<br>&nbsp;* ####################<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* #################<br>&nbsp;* # global macros #<br>&nbsp;* #################<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* ##############################<br>&nbsp;* # global abstract data types #<br>&nbsp;* ##############################<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* ####################<br>&nbsp;* # global variables #<br>&nbsp;* ####################<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* #############<br>&nbsp;* # externals #<br>&nbsp;* #############<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* ###############################<br>&nbsp;* # global functions prototypes #<br>&nbsp;* ###############################<br>&nbsp;*/</p>
<p>#endif ANSI_C_CODING_STANDARDS_H </p>
<p>//in ANSI_C_CODING_STANDARDS.c</p>
<p>/*<br>&nbsp;* Copyright 2005, XX, Inc., China<br>&nbsp;* All rights reserved. <br>&nbsp;*<br>&nbsp;* XX's source code is an unpublished work and the use of a copyright notice does <br>&nbsp;* not imply otherwise. This source code contains confidential, trade secret material of <br>&nbsp;* XX, Inc. Any attempt or participation in deciphering, decoding, reverse engineering<br>&nbsp;* or in any way altering the source code is strictly prohibited, unless the prior written <br>&nbsp;* consent of XX, Inc. is obtained.<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* @file ANSI_C_CODING_STANDARDS.c<br>&nbsp;* @author tony_bai<br>&nbsp;* @date 2005-07-01<br>&nbsp;* @brief the template for ANSI C<br>&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source file<br>&nbsp;*/</p>
<p>/* <br>&nbsp;* @revision<br>&nbsp;*&nbsp;&nbsp; @version 0.1<br>&nbsp;*&nbsp;&nbsp; @date 2005-08-01<br>&nbsp;*&nbsp;&nbsp; @Revisor tony_bai<br>&nbsp;*&nbsp;&nbsp; <br>&nbsp;* @revision<br>&nbsp;*&nbsp;&nbsp; @version 0.2<br>&nbsp;*&nbsp;&nbsp; @date 2005-09-01<br>&nbsp;*&nbsp;&nbsp; @Revisor tony_bai<br>&nbsp;*/</p>
<p>#include &lt;ANSI C Standard Library Header File&gt;<br>#include &lt;Operating System Library Header File&gt; <br>#include "Your System Library Header File"</p>
<p>/*<br>&nbsp;* ###################<br>&nbsp;* # local constants #<br>&nbsp;* ###################<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* ################<br>&nbsp;* # local macros #<br>&nbsp;* ################<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* #############################<br>&nbsp;* # local abstract data types #<br>&nbsp;* #############################<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* ###################<br>&nbsp;* # local variables #<br>&nbsp;* ###################<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* ##############################<br>&nbsp;* # local functions prototypes #<br>&nbsp;* ##############################<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* ####################################<br>&nbsp;* # global functions implementations #<br>&nbsp;* ####################################<br>&nbsp;*/</p>
<p>/*<br>&nbsp;* ###################################<br>&nbsp;* # local functions implementations #<br>&nbsp;* ###################################<br>&nbsp;*/</p>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/119105.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-05-22 13:23 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/05/22/119105.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GCC - 一切从这里开始(zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/05/22/119077.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Tue, 22 May 2007 03:24:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/05/22/119077.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/119077.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/05/22/119077.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/119077.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/119077.html</trackback:ping><description><![CDATA[<p><a href="http://www.linuxfocus.org/ChineseGB/March2002/article229.shtml">http://www.linuxfocus.org/ChineseGB/March2002/article229.shtml</a><br><br><em><br><br>摘要</em>:
<p>要想读懂本文，你需要对C语言有基本的了解，本文将介绍如何使用gcc编译器。首先，我们介绍如何在命令行方式下使用编译器编译简单的C源代码。然后，我们简要介绍一下编译器究竟作了那些工作，以及如何控制编译过程。我们也简要介绍了调试器的使用方法。 <br><br><!-- HR divider -->
<table width=300 align=center border=0>
    <tbody>
        <tr>
            <td bgColor=#8282e0><img height=2 alt="" src="http://www.linuxfocus.org/common/images/transpix.gif" width=1></td>
        </tr>
    </tbody>
</table>
<!-- BODY OF THE ARTICLE --><a name=229lfindex0>&nbsp;</a>
<h2>GCC rules </h2>
<p>你能想象使用封闭源代码的私有编译器编译自由软件吗？你怎么知道编译器在你的可执行文件中加入了什么？可能会加入各种后门和木马。Ken Thompson是一个著名的黑客，他编写了一个编译器，当编译器编译自己时，就在'login'程序中留下后门和永久的木马。请到 <a href="http://www.acm.org/classics/sep95"><u><font color=#0000ff>这里 </font></u></a>阅读他对这个杰作的描述。幸运的是，我们有了gcc。当你进行 <code>configure; make; make install </code>时， gcc在幕后做了很多繁重的工作。如何才能让gcc为我们工作呢？我们将开始编写一个纸牌游戏，不过我们只是为了演示编译器的功能，所以尽可能地精简了代码。我们将从头开始一步一步地做，以便理解编译过程，了解为了制作可执行文件需要做些什么，按什么顺序做。我们将看看如何编译C程序，以及如何使用编译选项让gcc按照我们的要求工作。步骤（以及所用工具）如下： <a href="http://www.linuxfocus.org/ChineseGB/March2002/article229.shtml#precomp"><u><font color=#800080>预编译 </font></u></a>(gcc -E)， <a href="http://www.linuxfocus.org/ChineseGB/March2002/article229.shtml#comp"><u><font color=#800080>编译 </font></u></a>(gcc)， <a href="http://www.linuxfocus.org/ChineseGB/March2002/article229.shtml#assem"><u><font color=#800080>汇编 </font></u></a>(as)，和 <a href="http://www.linuxfocus.org/ChineseGB/March2002/article229.shtml#link"><u><font color=#800080>连接 </font></u></a>(ld)。 </p>
<a name=229lfindex1>&nbsp;</a>
<h2>开始... </h2>
<p>首先，我们应该知道如何调用编译器。实际上，这很简单。我们将从那个著名的第一个C程序开始。（各位老前辈，请原谅我）。 </p>
<p>
<pre>#include &lt;stdio.h&gt;
int main()<br>
{
printf("Hello World!\n");
}
</pre>
<p>&#160;</p>
<p>把这个文件保存为 <code>game.c</code>。 你可以在命令行下编译它：
<pre>gcc game.c
</pre>
在默认情况下，C编译器将生成一个名为 <code>a.out</code> 的可执行文件。你可以键入如下命令运行它：
<pre>a.out
<strong>Hello World</strong>
</pre>
每一次编译程序时，新的 <code>a.out</code> 将覆盖原来的程序。你无法知道是哪个程序创建了 <code>a.out</code>。我们可以通过使用 <code>-o</code> 编译选项，告诉 gcc我们想把可执行文件叫什么名字。我们将把这个程序叫做 <code>game</code>，我们可以使用任何名字，因为C没有Java那样的命名限制。
<pre>gcc -o game game.c
</pre>
<pre>game
<strong>Hello World</strong>
</pre>
<p>&#160;</p>
<p>到现在为止，我们离一个有用的程序还差得很远。如果你觉得沮丧，你可以想一想我们已经编译并运行了一个程序。因为我们将一点一点为这个程序添加功能，所以我们必须保证让它能够运行。似乎每个刚开始学编程的程序员都想一下子编一个1000行的程序，然后一次修改所有的错误。没有人，我是说没有人，能做到这个。你应该先编一个可以运行的小程序，修改它，然后再次让它运行。这可以限制你一次修改的错误数量。另外，你知道刚才做了哪些修改使程序无法运行，因此你知道应该把注意力放在哪里。这可以防止这样的情况出现：你认为你编写的东西应该能够工作，它也能通过编译，但它就是不能运行。请切记，能够通过编译的程序并不意味着它是正确的。 </p>
<p>下一步为我们的游戏编写一个头文件。头文件把数据类型和函数声明集中到了一处。这可以保证数据结构定义的一致性，以便程序的每一部分都能以同样的方式看待一切事情。 </p>
<pre>#ifndef DECK_H
#define DECK_H
#define DECKSIZE 52
typedef struct deck_t
{
int card[DECKSIZE];
/* number of cards used */
int dealt;
}deck_t;
#endif /* DECK_H */
</pre>
<p>把这个文件保存为 <code>deck.h</code>。只能编译 <code>.c</code> 文件，所以我们必须修改 game.c。在game.c的第2行，写上 <code>#include "deck.h"</code>。在第5行写上 <code>deck_t deck;</code>。为了保证我们没有搞错，把它重新编译一次。
<pre>gcc -o game game.c
</pre>
<p>&#160;</p>
<p>如果没有错误，就没有问题。如果编译不能通过，那么就修改它直到能通过为止。 </p>
<a name=229lfindex2>&nbsp;</a>
<h2><a name=precomp>预编译 </a></h2>
<p>编译器是怎么知道 <code>deck_t</code> 类型是什么的呢？因为在预编译期间，它实际上把"deck.h"文件复制到了"game.c"文件中。源代码中的预编译指示以"#"为前缀。你可以通过在gcc后加上 <code>-E</code> 选项来调用预编译器。
<pre>gcc -E -o game_precompile.txt game.c
wc -l game_precompile.txt
3199 game_precompile.txt
</pre>
几乎有3200行的输出！其中大多数来自 <code>stdio.h</code> 包含文件，但是如果你查看这个文件的话，我们的声明也在那里。如果你不用 <code>-o</code> 选项指定输出文件名的话，它就输出到控制台。预编译过程通过完成三个主要任务给了代码很大的灵活性。
<ol>
    <li>把"include"的文件拷贝到要编译的源文件中。
    <li>用实际值替代"define"的文本。
    <li>在调用宏的地方进行宏替换。 </li>
</ol>
这就使你能够在整个源文件中使用符号常量（即用DECKSIZE表示一付牌中的纸牌数量），而符号常量是在一个地方定义的，如果它的值发生了变化，所有使用符号常量的地方都能自动更新。在实践中，你几乎不需要单独使用 <code>-E</code> 选项，而是让它把输出传送给编译器。
<p>&#160;</p>
<a name=229lfindex3>&nbsp;</a>
<h2><a name=comp>编译 </a></h2>
<p>作为一个中间步骤，gcc把你的代码翻译成汇编语言。它一定要这样做，它必须通过分析你的代码搞清楚你究竟想要做什么。如果你犯了语法错误，它就会告诉你，这样编译就失败了。人们有时会把这一步误解为整个过程。但是，实际上还有许多工作要gcc去做呢。 </p>
<a name=229lfindex4>&nbsp;</a>
<h2><a name=assem>汇编 </a></h2>
<p><code>as</code> 把汇编语言代码转换为目标代码。事实上目标代码并不能在CPU上运行，但它离完成已经很近了。编译器选项 <code>-c</code> 把 .c 文件转换为以 .o 为扩展名的目标文件。 如果我们运行
<pre>gcc -c game.c
</pre>
我们就自动创建了一个名为game.o的文件。这里我们碰到了一个重要的问题。我们可以用任意一个 .c 文件创建一个目标文件。正如我们在下面所看到的，在连接步骤中我们可以把这些目标文件组合成可执行文件。让我们继续介绍我们的例子。因为我们正在编写一个纸牌游戏，我们已经把一付牌定义为 <code>deck_t</code>，我们将编写一个洗牌函数。这个函数接受一个指向deck类型的指针，并把一付随机的牌装入deck类型。它使用'drawn' 数组跟踪记录那些牌已经用过了。这个具有DECKSIZE个元素的数组可以防止我们重复使用一张牌。
<p>&#160;</p>
<pre>#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;time.h&gt;
#include "deck.h"
static time_t seed = 0;
void shuffle(deck_t *pdeck)
{
/* Keeps track of what numbers have been used */
int drawn[DECKSIZE] = {0};
int i;
/* One time initialization of rand */
if(0 == seed)
{
seed = time(NULL);
srand(seed);
}
for(i = 0; i &lt; DECKSIZE; i++)
{
int value = -1;
do
{
value = rand() % DECKSIZE;
}
while(drawn[value] != 0);
/* mark value as used */
drawn[value] = 1;
/* debug statement */
printf("%i\n", value);
pdeck-&gt;card[i] = value;
}
pdeck-&gt;dealt = 0;
return;
}
</pre>
<p>把这个文件保存为 <code>shuffle.c</code>。我们在这个代码中加入了一条调试语句，以便运行时，能输出所产生的牌号。这并没有为我们的程序添加功能，但是现在到了关键时刻，我们看看究竟发生了什么。因为我们的游戏还在初级阶段，我们没有别的办法确定我们的函数是否实现了我们要求的功能。使用那条printf语句，我们就能准确地知道现在究竟发生了什么，以便在开始下一阶段之前我们知道牌已经洗好了。在我们对它的工作感到满意之后，我们可以把那一行语句从代码中删掉。这种调试程序的技术看起来很粗糙，但它使用最少的语句完成了调试任务。以后我们再介绍更复杂的调试器。 </p>
请注意两个问题。
<ol>
    <li>我们用传址方式传递参数，你可以从'&amp;'（取地址）操作符看出来。这把变量的机器地址传递给了函数，因此函数自己就能改变变量的值。也可以使用全局变量编写程序，但是应该尽量少使用全局变量。指针是C的一个重要组成部分，你应该充分地理解它。
    <li>我们在一个新的 .c 文件中使用函数调用。操作系统总是寻找名为'main'的函数，并从那里开始执行。 <code>shuffle.c</code> 中没有'main'函数，因此不能编译为独立的可执行文件。我们必须把它与另一个具有'main'函数并调用'shuffle'的程序组合起来。 </li>
</ol>
<p>运行命令
<pre>gcc -c shuffle.c
</pre>
并确定它创建了一个名为 <code>shuffle.o</code> 的新文件。编辑game.c文件，在第7行，在 deck_t类型的变量 <code>deck</code> 声明之后，加上下面这一行：
<pre>shuffle(&amp;deck);
</pre>
现在，如果我们还象以前一样创建可执行文件，我们就会得到一个错误
<pre>gcc -o game game.c
/tmp/ccmiHnJX.o: In function `main':
/tmp/ccmiHnJX.o(.text+0xf): undefined reference to `shuffle'
collect2: ld returned 1 exit status
</pre>
编译成功了，因为我们的语法是正确的。但是连接步骤却失败了，因为我们没有告诉编译器'shuffle'函数在哪里。那么，到底什么是连接？我们怎样告诉编译器到哪里寻找这个函数呢？
<p>&#160;</p>
<a name=229lfindex5>&nbsp;</a>
<h2><a name=link>连接 </a></h2>
<p>连接器<code>ld</code>，使用下面的命令，接受前面由 <code>as</code> 创建的目标文件并把它转换为可执行文件
<pre>gcc -o game game.o shuffle.o
</pre>
这将把两个目标文件组合起来并创建可执行文件 <code>game</code>。
<p>&#160;</p>
<p>连接器从shuffle.o目标文件中找到 <code>shuffle</code> 函数，并把它包括进可执行文件。目标文件的真正好处在于，如果我们想再次使用那个函数，我们所要做的就是包含"deck.h" 文件并把 <code>shuffle.o</code> 目标文件连接到新的可执行文件中。 </p>
<p>象这样的代码重用是经常发生的。虽然我们并没有编写前面作为调试语句调用的 <code>printf</code> 函数，连接器却能从我们用 <code>#include &lt;stdlib.h&gt;</code> 语句包含的文件中找到它的声明，并把存储在C库（/lib/libc.so.6）中的目标代码连接进来。这种方式使我们可以使用已能正确工作的其他人的函数，只关心我们所要解决的问题。这就是为什么头文件中一般只含有数据和函数声明，而没有函数体。一般，你可以为连接器创建目标文件或函数库，以便连接进可执行文件。我们的代码可能产生问题，因为在头文件中我们没有放入任何函数声明。为了确保一切顺利，我们还能做什么呢？ </p>
<a name=229lfindex6>&nbsp;</a>
<h2><a name=lasttwo>另外两个重要选项 </a></h2>
<p><code>-Wall</code> 选项可以打开所有类型的语法警告，以便帮助我们确定代码是正确的，并且尽可能实现可移植性。当我们使用这个选项编译我们的代码时，我们将看到下述警告：
<pre>game.c:9: warning: implicit declaration of function `shuffle'
</pre>
这让我们知道还有一些工作要做。我们需要在头文件中加入一行代码，以便告诉编译器有关 <code>shuffle</code> 函数的一切，让它可以做必要的检查。听起来象是一种狡辩，但这样做 可以把函数的定义与实现分离开来，使我们能在任何地方使用我们的函数，只要包含新的头文件 并把它连接到我们的目标文件中就可以了。下面我们就把这一行加入deck.h中。
<pre>void shuffle(deck_t *pdeck);
</pre>
这就可以消除那个警告信息了。
<p>&#160;</p>
<p>另一个常用编译器选项是优化选项 <code>-O#</code> (即 -O2)。 这是告诉编译器你需要什么级别的优化。编译器具有一整套技巧可以使你的代码运行得更快一点。对于象我们这种小程序，你可能注意不到差别，但对于大型程序来说，它可以大幅度提高运行速度。你会经常碰到它，所以你应该知道它的意思。 </p>
<a name=229lfindex7>&nbsp;</a>
<h2><a name=debug>调试 </a></h2>
<p>我们都知道，代码通过了编译并不意味着它按我们得要求工作了。你可以使用下面的命令验证是否所有的号码都被使用了
<pre>game | sort - n | less
</pre>
并且检查有没有遗漏。如果有问题我们该怎么办？我们如何才能深入底层查找错误呢？
<p>&#160;</p>
你可以使用调试器检查你的代码。大多数发行版都提供著名的调试器：gdb。如果那些众多的命令行选项让你感到无所适从，那么你可以使用KDE提供的一个很好的前端工具 <a href="http://members.nextra.at/johsixt/kdbg.html"><u><font color=#0000ff>KDbg</font></u></a>。还有一些其它的前端工具，它们都很相似。要开始调试，你可以选择 File-&gt;Executable 然后找到你的 <code>game</code> 程序。当你按下F5键或选择 Execution-&gt;从菜单运行时，你可以在另一个窗口中看到输出。怎么回事？在那个窗口中我们什么也看不到。不要担心，KDbg没有出问题。问题在于我们在可执行文件中没有加入任何调试信息，所以KDbg不能告诉我们内部发生了什么。编译器选项 <code>-g</code> 可以把必要的调试信息加入目标文件。你必须用这个选项编译目标文件（扩展名为.o），所以命令行成了：
<pre>gcc -g -c shuffle.c game.c
gcc -g -o game game.o shuffle.o
</pre>
这就把钩子放入了可执行文件，使gdb和KDbg能指出运行情况。调试是一种很重要的技术，很值得你花时间学习如何使用。调试器帮助程序员的方法是它能在源代码中设置&#8220;断点&#8221;。现在你可以用右键单击调用 <code>shuffle</code> 函数的那行代码，试着设置断点。那一行边上会出现一个红色的小圆圈。现在当你按下F5键时，程序就会在那一行停止执行。按F8可以跳入shuffle函数。呵，我们现在可以看到 <code>shuffle.c</code> 中的代码了！我们可以控制程序一步一步地执行，并看到究竟发生了什么事。如果你把光标暂停在局部变量上，你将能看到变量的内容。太好了。这比那条 <code>printf</code> 语句好多了，是不是？
<p>&#160;</p>
<a name=229lfindex8>&nbsp;</a>
<h2>小结 </h2>
<p>本文大体介绍了编译和调试C程序的方法。我们讨论了编译器走过的步骤，以及为了让编译器做这些工作应该给gcc传递哪些选项。我们简述了有关连接共享函数库的问题，最后介绍了调试器。真正了解你所从事的工作还需要付出许多努力，但我希望本文能让你正确地起步。你可以在 <code>gcc</code>、 <code>as</code> 和 <code>ld</code>的 <code>man</code> 和 <code>info</code> page中找到更多的信息。 </p>
<p>自己编写代码可以让你学到更多的东西。作为练习你可以以本文的纸牌游戏为基础，编写一个21点游戏。那时你可以学学如何使用调试器。使用GUI的KDbg开始可以更容易一些。如果你每次只加入一点点功能，那么很快就能完成。切记，一定要保持程序一直能运行！
<p>要想编写一个完整的游戏，你需要下面这些内容：
<ul>
    <li>一个纸牌玩家的定义（即，你可以把deck_t定义为player_t）。
    <li>一个给指定玩家发一定数量牌的函数。记住在纸牌中要增加&#8220;已发牌&#8221;的数量，以便能知道还有那些牌可发。还要记住玩家手中还有多少牌。
    <li>一些与用户的交互，问问玩家是否还要另一张牌。
    <li>一个能打印玩家手中的牌的函数。 <em>card</em> 等于value % 13 （得数为0到12），<em>suit</em> 等于 value / 13 （得数为0到3）。
    <li>一个能确定玩家手中的value的函数。Ace的value为零并且可以等于1或11。King的value为12并且可以等于10。 </li>
</ul>
<p>&#160;</p>
<p>&#160;</p>
<a name=229lfindex9>&nbsp;</a>
<h2><a name=links>站点链接 </a></h2>
<ul>
    <li><a href="http://www.gnu.org/directory/gcc.html"><u><font color=#0000ff>gcc</font></u></a> GCC GNU Compiler Collection
    <li><a href="http://www.gnu.org/directory/gdb.html"><u><font color=#0000ff>gdb</font></u></a> GNU Debugger
    <li><a href="http://members.nextra.at/johsixt/kdbg.html"><u><font color=#0000ff>KDbg</font></u></a> KDE's GUI Debugger
    <li><a href="http://www.acm.org/classics/sep95"><u><font color=#0000ff>Award Winning Compiler Hack</font></u></a> Ken Thompson's great compiler hack </li>
</ul>
<!-- vim: set sw=2 ts=2 et tw=74: --><!-- 2pdaIgnoreStart -->
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/119077.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-05-22 11:24 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/05/22/119077.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>