﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-大龙的博客</title><link>http://www.cppblog.com/fwxjj/</link><description /><language>zh-cn</language><lastBuildDate>Mon, 01 Dec 2008 17:08:56 GMT</lastBuildDate><pubDate>Mon, 01 Dec 2008 17:08:56 GMT</pubDate><ttl>60</ttl><item><title>查看目录大小</title><link>http://www.cppblog.com/fwxjj/archive/2008/11/18/67190.html</link><dc:creator>大龙1</dc:creator><author>大龙1</author><pubDate>Tue, 18 Nov 2008 02:39:00 GMT</pubDate><guid>http://www.cppblog.com/fwxjj/archive/2008/11/18/67190.html</guid><wfw:comment>http://www.cppblog.com/fwxjj/comments/67190.html</wfw:comment><comments>http://www.cppblog.com/fwxjj/archive/2008/11/18/67190.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/fwxjj/comments/commentRss/67190.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/fwxjj/services/trackbacks/67190.html</trackback:ping><description><![CDATA[du -sh /home
<img src ="http://www.cppblog.com/fwxjj/aggbug/67190.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fwxjj/" target="_blank">大龙1</a> 2008-11-18 10:39 <a href="http://www.cppblog.com/fwxjj/archive/2008/11/18/67190.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C/C++中利用空指针简化代码,提高效率   ----- 转</title><link>http://www.cppblog.com/fwxjj/archive/2008/11/08/66304.html</link><dc:creator>大龙1</dc:creator><author>大龙1</author><pubDate>Sat, 08 Nov 2008 02:50:00 GMT</pubDate><guid>http://www.cppblog.com/fwxjj/archive/2008/11/08/66304.html</guid><wfw:comment>http://www.cppblog.com/fwxjj/comments/66304.html</wfw:comment><comments>http://www.cppblog.com/fwxjj/archive/2008/11/08/66304.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/fwxjj/comments/commentRss/66304.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/fwxjj/services/trackbacks/66304.html</trackback:ping><description><![CDATA[<p class=code clear=both><font color=#000000>#include&nbsp;&lt;iostream&gt;&nbsp;&nbsp;&nbsp; <br>#include&nbsp;&lt;string&gt;&nbsp;&nbsp;&nbsp; <br>using&nbsp;namespace&nbsp;std;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; <br>void&nbsp;print_char(char*&nbsp;array[]);//函数原形声明&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; <br>void&nbsp;main(void)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;char*&nbsp;test[]=;//这里添加一个NULL,表示不指向任何地址,值为0&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;print_char(test);&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;cin.get();&nbsp;&nbsp;&nbsp; <br>}&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; <br>void&nbsp;print_char(char*&nbsp;array[])&nbsp;&nbsp;&nbsp; <br>{&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;while(*array!=NULL)&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;*array++&lt;&lt;endl;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp; <br>}&nbsp;</font></p>
<br>自己的理解为: <br>注:如果用for循环,那么里面有循环变量，要经过读,改,写.
<img src ="http://www.cppblog.com/fwxjj/aggbug/66304.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fwxjj/" target="_blank">大龙1</a> 2008-11-08 10:50 <a href="http://www.cppblog.com/fwxjj/archive/2008/11/08/66304.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>锁无关的（Lock-Free）数据结构  ----  转</title><link>http://www.cppblog.com/fwxjj/archive/2008/11/07/66257.html</link><dc:creator>大龙1</dc:creator><author>大龙1</author><pubDate>Fri, 07 Nov 2008 15:07:00 GMT</pubDate><guid>http://www.cppblog.com/fwxjj/archive/2008/11/07/66257.html</guid><wfw:comment>http://www.cppblog.com/fwxjj/comments/66257.html</wfw:comment><comments>http://www.cppblog.com/fwxjj/archive/2008/11/07/66257.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/fwxjj/comments/commentRss/66257.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/fwxjj/services/trackbacks/66257.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 锁无关的（Lock-Free）数据结构 1peakzhang 发表于: 2008-4-23 23:31来源: ACE 开发者C/C++ Users Journal October, 2004锁无关的（Lock-Free）数据结构在避免死锁的同时确保线程继续http://blog.csdn.net/pongba/archive/2006/01/26/58863...&nbsp;&nbsp;<a href='http://www.cppblog.com/fwxjj/archive/2008/11/07/66257.html'>阅读全文</a><img src ="http://www.cppblog.com/fwxjj/aggbug/66257.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fwxjj/" target="_blank">大龙1</a> 2008-11-07 23:07 <a href="http://www.cppblog.com/fwxjj/archive/2008/11/07/66257.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>异常处理     ------  转</title><link>http://www.cppblog.com/fwxjj/archive/2008/11/07/66251.html</link><dc:creator>大龙1</dc:creator><author>大龙1</author><pubDate>Fri, 07 Nov 2008 14:41:00 GMT</pubDate><guid>http://www.cppblog.com/fwxjj/archive/2008/11/07/66251.html</guid><wfw:comment>http://www.cppblog.com/fwxjj/comments/66251.html</wfw:comment><comments>http://www.cppblog.com/fwxjj/archive/2008/11/07/66251.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/fwxjj/comments/commentRss/66251.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/fwxjj/services/trackbacks/66251.html</trackback:ping><description><![CDATA[<p>潜心研究C++异常处理机制数日,有所得,与大家共享: <br>
<br>
C++异常处理机制核心观点: <br>
<br>
0.如果使用普通的处理方式:ASSERT,return等已经 <br>
&nbsp;&nbsp;  足够简洁明了,请不要使用异常处理机制. <br>
<br>
1.比C的setjump,longjump优秀. <br>
<br>
2.可以处理任意类型的异常. <br>
&nbsp;&nbsp;  你可以人为地<a name="baidusnap3"></a><strong style="color: black; background-color: #ff9999;">抛出</strong>任何类型的对象作为异常. <br>
&nbsp;&nbsp;  throw 100; <br>
&nbsp;&nbsp;  throw "hello"; <br>
&nbsp;&nbsp;  ... <br>
<br>
3.需要一定的开销,频繁执行的关键代码段避免使用 <br>
&nbsp;&nbsp;  C++异常处理机制. <br>
<br>
4.其强大的能力表现在: <br>
&nbsp;&nbsp;  A.把可能出现异常的代码和异常处理代码隔离开,结构更清晰. <br>
&nbsp;&nbsp;  B.把内层错误的处理直接转移到适当的外层来处理,化简了处理 <br>
&nbsp;&nbsp;&nbsp;&nbsp;  流程.传统的手段是通过一层层返回错误码把错误处理转移到 <br>
&nbsp;&nbsp;&nbsp;  上层,上层再转移到上上层,当层数过多时将需要非常多的判断, <br>
&nbsp;&nbsp;&nbsp;  以采取适当的策略. <br>
&nbsp;&nbsp;  C.局部出现异常时,在执行处理代码之前,会执行堆栈回退,即为 <br>
&nbsp;&nbsp;&nbsp;&nbsp;  所有局部对象调用<a name="baidusnap6"></a><strong style="color: white; background-color: #00aa00;">析构函数</strong>,保证局部对象行为良好. <br>
&nbsp;&nbsp;  D.可以在出现异常时保证不产生内存泄漏.通过适当的try,catch <br>
&nbsp;&nbsp;&nbsp;&nbsp;  布局,可以保证delete pobj;一定被执行. <br>
<br>
&nbsp;&nbsp;  E.在出现异常时,能够获取异常的信息,指出异常原因. <br>
&nbsp;&nbsp;&nbsp;&nbsp;  并可以给用户优雅的提示. <br>
&nbsp;&nbsp;  F.可以在处理块中尝试错误恢复.保证程序几乎不会崩溃. <br>
&nbsp;&nbsp;&nbsp;&nbsp;  通过适当处理,即使出现除0异常,内存访问违例,也能 <br>
&nbsp;&nbsp;&nbsp;&nbsp;  让程序不崩溃,继续运行,这种能力在某些情况下及其重要. <br>
<br>
以上ABCDEF可以使你的程序更稳固,健壮,不过有时让程序崩溃似乎更 <br>
容易找到原因,程序老是不崩溃,如果处理结果有问题,有时很难查找. <br>
<br>
5.并不是只适合于处理'灾难性的'事件.普通的错误处理也可以用异常机制 <br>
&nbsp;&nbsp;  来处理,不过如果将此滥用的话,可能造成程序结构混乱, <br>
&nbsp;&nbsp;  因为异常处理机制本质上是程序处理流程的转移,不恰当的,过度的转移显然 <br>
&nbsp;&nbsp;  将造成混乱.许多人认为应该只在'灾难性的'事件上使用异常处理,以避免异常 <br>
&nbsp;&nbsp;  处理机制本身带来的开销,你可以认为这句话通常是对的. <br>
<br>
6.先让程序更脆弱,再让程序更坚强.首先,它使程序非常脆弱,稍有差错,马上 <br>
&nbsp;&nbsp;  执行流程跳转掉,去寻找相应的处理代码,以求适当的解决方式. <br>
&nbsp;&nbsp;  很像一个人身上带着许多药品,防护工具出行,稍有头晕,马上拿出清凉油; <br>
&nbsp;&nbsp;  遇到蚊子立刻拿出电蚊拍灭之. <br>
<br>
WINDOWS: <br>
7.将结构化异常处理结合/转换到C++异常对象,可以更好地处理WINDOWS程序 <br>
&nbsp;&nbsp;  出现的异常. <br>
8.尽一切可能使用try,catch,而不是win32本身的结构化异常处理或者 <br>
&nbsp;&nbsp;  MFC中的TRY,CATCH宏. <br>
<br>
用得恰到好处,方显C++异常之美妙!</p>
<p> </p>
<p> </p>
<p> </p>
<p><font size="2">1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  异常处理的使用</font></p>
<p><font size="2">首先说明，千万别对异常处理钻牛角尖，那样会死人的（当然是烦死的）！</font></p>
<p><font size="2">在C++编程处理中，我秉承这样一个思想，就是：能不用异常处理的就不用。因为造成的混乱实在是太——多了。如果能
用其他方法捕捉到错误并处理的话，誓死不用异常处理！呵呵，或许有点偏激，但我认为，这不失为一个避免不必要的错误的一个好办法。当什么分配内存失败，打
开文件失败之类的通常错误，我们只需用assert，abort之类的函数就解决问题了。也就是说，假如有足够的信息去处理一个错误，那么这个错误就不是
异常。</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  当然了，异常处理的存在也有它本身的意义和作用。不是你说不用就不用的，有些地方还非得用不可！</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  比如说，在当前上下文环境中，无法捕捉或确定的错误类型，我们就得用<a name="baidusnap4"></a><strong style="color: black; background-color: #ff66ff;">一个异常</strong><strong style="color: black; background-color: #ff9999;">抛出</strong>到更大的上下文环境当中去。还有，异常处理的使用呢，可以使出错处理程序与&#8220;通常&#8221;代码分离开来，使代码更简洁更灵活。另外就是程序必不可少的健壮性了，异常处理往往在其中扮演着重要的角色。</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  OK，下面阐述一下。</font></p>
<p><font size="2">2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <strong style="color: black; background-color: #ff9999;">抛出</strong>异常</font></p>
<p><font size="2">关——键字（周星驰的语气）：throw</font></p>
<p><font size="2">例——句：throw ExceptionClass(&#8220;oh, shit! it&#8217;s a exception!L &#8220;);</font></p>
<p><font size="2">例句中，ExceptionClass是一个类，它的构造函数以一个字符串做为参数，用来说明异常。也就是说，在throw的时候，<a name="baidusnap0"></a><strong style="color: black; background-color: #ffff66;">C++的</strong>编译器先构造一个ExceptionClass的对象，让它作为throw的返回值，抛——出去。同时，程序返回，调用析构。看下面这个程序：</font></p>
<p><font size="2">#include &lt;iostream.h&gt;</font></p>
<p> </p>
<p><font size="2">class ExceptionClass{</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  char* name;</font></p>
<p><font size="2">public:</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ExceptionClass(char* name="default name")&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout&lt;&lt;"Construct "&lt;&lt;name&lt;&lt;endl;</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  this-&gt;name=name;</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ~ExceptionClass()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout&lt;&lt;"Destruct "&lt;&lt;name&lt;&lt;endl;</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  void mythrow(){</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  throw ExceptionClass("o,my god");</font></p>
<p><font size="2">}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font></p>
<p><font size="2">};</font></p>
<p> </p>
<p><font size="2">void main(){</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ExceptionClass e("haha");</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  try&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  e.mythrow();</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  catch(...)&nbsp;&nbsp;&nbsp;&nbsp;  {</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</font></p>
<p><font size="2">}</font></p>
<p><font size="2">大家看看结果就知道了，throw后，调用当前类的析构，整个结束了这个类的历史使命。唉~~</font></p>
<p><font size="2">3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  异常规格说明</font></p>
<p><font size="2">如果我们调用别人的函数，里面有异常<strong style="color: black; background-color: #ff9999;">抛出</strong>，我用去查看它的源代码去看看都有什么异常<strong style="color: black; background-color: #ff9999;">抛出</strong>吗？可以，但是太——烦躁。比较好的解决办法，是编写带有异常<strong style="color: black; background-color: #ff9999;">抛出</strong>的函数时，采用异常规格说明，使我们看到函数声明就知道有哪些异常出现。</font></p>
<p><font size="2">异常规格说明大体上为以下格式：</font></p>
<p><font size="2">void ExceptionFunction(argument&#8230;) throw(ExceptionClass1, ExceptionClass2, &#8230;.)</font></p>
<p><font size="2">对了，所有异常类都在函数末尾的throw()的括号中得以说明了，这样，对于函数调用者来说，是一清二楚了！</font></p>
<p><font size="2">注意下面一种形式：</font></p>
<p><font size="2">void ExceptionFunction(argument&#8230;) throw()</font></p>
<p><font size="2">表明没有任何异常<strong style="color: black; background-color: #ff9999;">抛出</strong>。</font></p>
<p><font size="2">而正常的void ExceptionFunction(argument&#8230;)则表示：可能<strong style="color: black; background-color: #ff9999;">抛出</strong>任何一种异常，当然就，也可能没有异常，意义是最广泛的哦。</font></p>
<p><font size="2">4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  构造和析构中的异常<strong style="color: black; background-color: #ff9999;">抛出</strong></font></p>
<p><font size="2">55555，到了应该注意的地方了。</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  先看个程序，假如我在构造函数的地方<strong style="color: black; background-color: #ff9999;">抛出</strong>异常，这个类的析构会被调用吗？可如果不调用，那类里的东西岂不是不能被释放了？？</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  程序：</font></p>
<p><font size="2">#include &lt;iostream.h&gt;</font></p>
<p><font size="2">#include &lt;stdlib.h&gt;</font></p>
<p> </p>
<p><font size="2">class ExceptionClass1{</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  char* s;</font></p>
<p><font size="2">public:</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ExceptionClass1(){</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout&lt;&lt;"ExceptionClass1()"&lt;&lt;endl;</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  s=new char[4];</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout&lt;&lt;"throw a exception"&lt;&lt;endl;</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  throw 18;</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ~ExceptionClass1(){</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout&lt;&lt;"~ExceptionClass1()"&lt;&lt;endl;</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete[] s;</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</font></p>
<p><font size="2">};</font></p>
<p> </p>
<p><font size="2">void main(){</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  try{</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ExceptionClass1 e;</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }catch(...)</font></p>
<p><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {}</font></p>
<p><font size="2">}</font></p>
<p><font size="2">结果为：</font></p>
<p><font size="2">ExceptionClass1()</font></p>
<p><font size="2">throw a exception</font></p>
<p><font size="2">没了，没了，到此为止了！可是，可是，在这两句输出之间，我们已经给S分配了内存，哪里去了？内存释放了吗？没有，没有，因为它是在<strong style="color: white; background-color: #00aa00;">析构函数</strong>中释放的，哇！问题大了去了。怎么办？怎么办？</font></p>
<p><font size="2">为了避免这种情况，应避免对象通过本身的构造函数涉及到异常<strong style="color: black; background-color: #ff9999;">抛出</strong>。即：既不在构造函数中出现异常<strong style="color: black; background-color: #ff9999;">抛出</strong>，也不应在构造函数调用的一切东西中出现异常<strong style="color: black; background-color: #ff9999;">抛出</strong>。否则，只有完蛋。</font></p>
<p><font size="2">那么，在<strong style="color: white; background-color: #00aa00;">析构函数</strong>中的情况呢？我们已经知道，异常<strong style="color: black; background-color: #ff9999;">抛出</strong>之后，就要调用本身的<strong style="color: white; background-color: #00aa00;">析构函数</strong>，如果这<strong style="color: white; background-color: #00aa00;">析构函数</strong>中还有异常<strong style="color: black; background-color: #ff9999;">抛出</strong>的话，则已存在的异常尚未被捕获，会导致异常捕捉不到哩。</font></p>
<p><font size="2">完，也就是说，我们不要在构造函数和<strong style="color: white; background-color: #00aa00;">析构函数</strong>中存在异常<strong style="color: black; background-color: #ff9999;">抛出</strong>。</font></p>
<p><font size="2">5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  异常捕获</font></p>
<p><font size="2">上边的程序不知道大家看懂了没，异常捕获已经在上面出现了也。</font></p>
<p><font size="2">没错，就是try{&#8230;}catch(&#8230;){&#8230;}这样的结构！</font></p>
<p><font size="2">Try后面的花括号中，就是有可能涉及到异常的各种声明啊调用啊之类的，如果有异常<strong style="color: black; background-color: #ff9999;">抛出</strong>，就会被异常处理器截获捕捉到，转给catch处理。先把异常的类和catch后面小括号中的类进行比较，如果一致，就转到后面的花括号中进行处理。</font></p>
<p><font size="2">例如<strong style="color: black; background-color: #ff9999;">抛出</strong>异常是这么写的：</font></p>
<p><font size="2">void f(){throw ExceptionClass(&#8220;ya, J&#8221;);}</font></p>
<p><font size="2">假设类ExceptionClass有个成员函数function()在有异常时进行处理或相应的消息显示（只是做个例子哦，别挑我的刺儿）。</font></p>
<p><font size="2">那么，我可以这么捕捉: try{f()}catch(ExceptionClass e){e.function()};</font></p>
<p><font size="2">当然，象在上面程序中出现的一样，我可以在catch后用三个点来代表所有异常。如try{f()}catch(&#8230;){}。这样就截断了所有出现的异常。有助于把所有没出现处理的异常屏蔽掉（我是这么认为的J）。</font></p>
<p><font size="2">异常捕获之后，我可以再次<strong style="color: black; background-color: #ff9999;">抛出</strong>，就用一个不带任何参数的throw语句就可以了，例如：try(f())catch(&#8230;){throw}</font></p>
<p> </p>
<p><font size="2">6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  标准异常</font></p>
<p><font size="2">正象许多人想象的一样，C++肯定有自己的标准的异常类。</font></p>
<p><font size="2">一个总基类：</font></p>
<p><font size="2">exception&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  是所有C++异常的基类。</font></p>
<p><font size="2">下面派生了两个异常类：</font></p>
<p><font size="2">logic_erro&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  报告程序的逻辑错误，可在程序执行前被检测到。</font></p>
<p><font size="2">runtime_erro&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  顾名思义，报告程序运行时的错误，只有在运行的时候才能检测到。</font></p>
<p><font size="2">以上两个又分别有自己的派生类：</font></p>
<p><font size="2">由logic_erro派生的异常类</font></p>
<p><font size="2">domain_error&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  报告违反了前置条件</font></p>
<p><font size="2">invalid_argument&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  指出函数的一个无效参数</font></p>
<p><font size="2">length_error 指出有一个产生超过NPOS长度的对象的企图（NPOS为size_t的最大可表现值</font></p>
<p><font size="2">out_of_range 报告参数越界</font></p>
<p><font size="2">bad_cast&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  在运行时类型识别中有一个无效的dynamic_cast表达式</font></p>
<p><font size="2">bad_typeid 报告在表达式typeid(*p)中有一个空指针P</font></p>
<p> </p>
<p><font size="2">由runtime_error派生的异常</font></p>
<p><font size="2">range_error 报告违反了后置条件</font></p>
<p><font size="2">overflow_error 报告一个算术溢出</font></p>
<p><font size="2">bad_alloc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  报告一个存储分配错误</font></p>
<p> </p>
<p><font size="2">呼呼，这是我这两天研究异常的总结报告。呼呼，累。<br>
</font></p>
<p> </p>
<font size="2">
</font>
<div class="tit"><font size="2">C++编译器如何实现异常处理1 －－ 摘自互联网</font></div>
<div class="date"><font size="2"> </font></div>
<div class="cnt">&nbsp;&nbsp;&nbsp;  与传统语言相比，<strong style="color: black; background-color: #ffff66;">C++的</strong>一
项革命性创新就是它支持异常处理。传统的错误处理方式经常满足不了要求，而异常处理则是一个极好的替代解决方案。它将正常
代码和错误处理代码清晰的划分开来，程序变得非常干净并且容易维护。本文讨论了编译器如何实现异常处理。我将假定你已经熟悉异常处理的语法和机制。本文还
提供了一个用于V<strong style="color: black; background-color: #ffff66;">C++的</strong>异常处理库，要用库中的处理程序替换掉VC++提供的那个，你只需要调用下面这个函数：
<p>
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#ffcc66">
    <tbody>
        <tr>
            <td><span class="bluekey"><u><font color="#0000ff">install</font></u></span>_my_handler();</td>
        </tr>
    </tbody>
</table>
<br>
之后，程序中的所有异常，从它们被<strong style="color: black; background-color: #ff9999;">抛出</strong>到堆栈展开（stack unwinding），再到调用catch块，最后到程序恢复正常运行，都将由我的异常处理库来管理。 <br>
<br>
与其它C++特性一样，C++标准并没有规定编译器应该如何来实现异常处理。这意味着每一个编译器的提供商都可以用它们认为恰当的方式来实现它。下面我
会描述一下VC++是怎么做的，但即使你使用其它的编译器或操作系统①，本文也应该会是一篇很好的学习材料。V<strong style="color: black; background-color: #ffff66;">C++的</strong>实现方式是以windows系统的 结构化异常处理（SEH）②为基础的。 <br>
<br>
<strong>结构化异常处理—概述</strong><br>
<br>
在本文的讨论中，我认为异常或者是被明确的<strong style="color: black; background-color: #ff9999;">抛出</strong>的，
或者是
由于除零溢出、空指针访问等引起的。当它发生时会产生一个中断，接下来控制权就会传递到操作系统的手中。操作系统将调用异常处理程序，检查从异常发生位置
开始的函数调用序列，进行堆栈展开和控制权转移。Windows定义了结构&#8220;EXCEPTION_REGISTRATION&#8221;，使我们能够向操作系统注册
自己的异常处理程序。 <br>
<br>
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#ffcc66">
    <tbody>
        <tr>
            <td><a  href="http://www.yesky.com/key/2457/102457.html" class="bluekey" target="_blank"><u><font color="#0000ff">struct</font></u></a> EXCEPTION_REGISTRATION<br>
            {<br>
            EXCEPTION_REGISTRATION* prev;<br>
            DWORD handler;<br>
            };</td>
        </tr>
    </tbody>
</table>
<br>
注册时，只需要创建这样一个结构，然后把它的地址放到FS段偏移0的位置上去就行了。下面这句汇编代码演示了这一操作：<br>
mov FS:[0], exc_regp<br>
<br>
prev字段用于建立一个EXCEPTION_REGISTRATION结构的链表，每次注册新的EXCEPTION_REGISTRATION时，我们都要把原来注册的那个的地址存到prev中。 <br>
<br>
那么，那个异常<a  href="http://www.yesky.com/key/2396/12396.html" class="bluekey" target="_blank"><u><font color="#0000ff">回调函数</font></u></a>长什么样呢？在excpt.h中，windows定义了它的原形：<br>
<br>
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#ffcc66">
    <tbody>
        <tr>
            <td>EXCEPTION_DISPOSITION (*handler)( <br>
            _EXCEPTION_RECORD *ExcRecord, <br>
            void* EstablisherFrame, <br>
            _CONTEXT *ContextRecord, <br>
            void* DispatcherContext);</td>
        </tr>
    </tbody>
</table>
<br>
不要管它的参数和返回值，我们先来看一个简单的例子。下面的程序注册了<strong style="color: black; background-color: #ff66ff;">一个异常</strong>处理程序，然后通过除以零产生了<strong style="color: black; background-color: #ff66ff;">一个异常</strong>。异常处理程序捕获了它，打印了一条消息就完事大吉并退出了。<br>
<br>
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#ffcc66">
    <tbody>
        <tr>
            <td>#include &lt;iostream&gt; <br>
            #include &lt;windows.h&gt; <br>
            <br>
            <a  href="http://www.yesky.com/key/437/100437.html" class="bluekey" target="_blank"><u><font color="#0000ff">using</font></u></a> std::cout; <br>
            using std::endl; <br>
            <br>
            struct EXCEPTION_REGISTRATION <br>
            { <br>
            EXCEPTION_REGISTRATION* prev; <br>
            DWORD handler; <br>
            }; <br>
            <br>
            EXCEPTION_DISPOSITION myHandler( <br>
            _EXCEPTION_RECORD *ExcRecord, <br>
            void * EstablisherFrame, <br>
            _CONTEXT *ContextRecord, <br>
            void * DispatcherContext) <br>
            { <br>
            cout &lt;&lt; "In the exception handler" &lt;&lt; endl; <br>
            cout &lt;&lt; "Just a demo. exiting..." &lt;&lt; endl; <br>
            exit(0); <br>
            return ExceptionContinueExecution; //不会运行到这 <br>
            } <br>
            <br>
            int g_div = 0; <br>
            <br>
            void bar() <br>
            { <br>
            //初始化一个EXCEPTION_REGISTRATION结构 <br>
            EXCEPTION_REGISTRATION reg, *preg = ? <br>
            reg.handler = (DWORD)myHandler; <br>
            <br>
            //取得当前异常处理链的&#8220;头&#8221; <br>
            DWORD prev; <br>
            _asm <br>
            { <br>
            mov <a  href="http://www.yesky.com/key/3687/38687.html" class="bluekey" target="_blank"><u><font color="#0000ff">EAX</font></u></a>, FS:[0] <br>
            mov prev, EAX <br>
            } <br>
            reg.prev = (EXCEPTION_REGISTRATION*) prev; <br>
            <br>
            //注册！ <br>
            _asm <br>
            { <br>
            mov EAX, preg <br>
            mov FS:[0], EAX <br>
            } <br>
            <br>
            //产生<strong style="color: black; background-color: #ff66ff;">一个异常</strong> <br>
            int j = 10 / g_div; //异常，除零溢出 <br>
            } <br>
            <br>
            int main() <br>
            { <br>
            bar(); <br>
            return 0; <br>
            } <br>
            <br>
            /*-------输出------------------- <br>
            In the exception handler <br>
            Just a demo. exiting... <br>
            ---------------------------------*/</td>
        </tr>
    </tbody>
</table>
<br>
注意EXCEPTION_REGISTRATION必须定义在栈上，并且必须位于比上一个结点更低的内存地址上，Windows对此有严格要求，达不到的话，它就会立刻终止进程。<br>
<strong>函数和堆栈</strong><br>
<br>
堆栈是用来保存局部对象的连续内存区。更明确的说，每个函数都有一个相关的栈桢（stack
frame）来保存它所有的局部对象和表达式计算过程中用到的临时对象，至少理论上是这样的。但现实中，编译器经常会把一些对象放到寄存器中以便能以更快
的速度访问。堆栈是一个处理器（CPU）层次的概念，为了操纵它，处理器提供了一些专用的寄存器和指令。 <br>
<br>
图1是一个典型的堆栈，它示出了函数foo调用bar，bar又调用widget时的情景。请注意堆栈是向下增长的，这意味着新压入的项的地址低于原有项的地址。<br>
<br>
<br>
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center">
            <div forimg="1"><img  src="http://hiphotos.baidu.com/page%5Freadonly/pic/item/3a8c4d241d96922ed507424a.jpg" class="blogimg" small="0" border="0"></div>
            </div>
            </td>
        </tr>
    </tbody>
</table>
<br>
通常编译器使用EBP寄存器来指示当前活动的栈桢。本例中，CPU正在运行widget，所以图中的EBP指向了widget的栈桢。编译器在编译时将
所有局部对象解析成相对于栈桢指针（EBP）的固定偏移，函数则通过栈桢指针来间接访问局部对象。举个例子，典型的，widget访问它的局部变量时就是
通过访问栈桢指针以下的、有着确定位置的几个字节来实现的，比如说EBP-24。 <br>
<br>
上图中也画出了ESP寄存器，它叫栈指针，指向栈的最后一项。在本例中，ESP指着widget的栈桢的末尾，这也是下一个栈桢（如果它被创建的话）的开始位置。 <br>
<br>
处理器支持两种类型的栈操作：压栈（push）和弹栈（pop）。比如，pop
EAX的作用是从ESP所指的位置读出4字节放到EAX寄存器中，并把ESP加上（记住，栈是向下增长的）4（在32位处理器上）；类似的，push
EBP的作用是把ESP减去4，然后将EBP的值放到ESP指向的位置中去。 <br>
<br>
编译器编译一个函数时，会在它的开头添加一些代码来为其创建并初始化栈桢，这些代码被称为序言（prologue）；同样，它也会在函数的结尾处放上代码来清除栈桢，这些代码叫做尾声（epilogue）。 <br>
<br>
一般情况下，序言是这样的：<br>
<br>
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#ffcc66">
    <tbody>
        <tr>
            <td>Push EBP ; 把原来的栈桢指针保存到栈上 <br>
            Mov EBP, ESP ; 激活新的栈桢 <br>
            Sub ESP, 10 ; 减去一个数字，让ESP指向栈桢的末尾</td>
        </tr>
    </tbody>
</table>
<br>
第一条指令把原来的栈桢指针EBP保存到栈上；第二条指令通过让EBP指向主调函数的EBP的保存位置来激活被调函数的栈桢；第三条指令把ESP减去了
一个数字，这样ESP就指向了当前栈桢的末尾，而这个数字是函数要用到的所有局部对象和临时对象的大小。编译时，编译器知道函数的所有局部对象的类型和
&#8220;体积&#8221;，所以，它能很容易的计算出栈桢的大小。 <br>
<br>
尾声所做的正好和序言相反，它必须把当前栈桢从栈上清除掉：<br>
<br>
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#ffcc66">
    <tbody>
        <tr>
            <td>Mov ESP, EBP <br>
            Pop EBP ; 激活主调函数的栈桢 <br>
            Ret ; 返回主调函数</td>
        </tr>
    </tbody>
</table>
<br>
它让ESP指向主调函数的栈桢指针的保存位置（也就是被调函数的栈桢指针指向的位置），弹出EBP从而激活主调函数的栈桢，然后返回主调函数。 <br>
<br>
一旦CPU遇到返回指令，它就要做以下两件事：把返回地址从栈中弹出，然后跳转到那个地址去。返回地址是主调函数执行call指令调用被调函数时自动压
栈的。Call指令执行时，会先把紧随在它后面的那条指令的地址（被调函数的返回地址）压入栈中，然后跳转到被调函数的开始位置。图2更详细的描绘了运行
时的堆栈。如图所示，主调函数把被调函数的参数也压进了堆栈，所以参数也是栈桢的一部分。函数返回后，主调函数需要移除这些参数，它通过把所有参数的总体
积加到ESP上来达到目的，而这个体积可以在编译时知道： <br>
<br>
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#ffcc66">
    <tbody>
        <tr>
            <td>Add ESP, args_size</td>
        </tr>
    </tbody>
</table>
<br>
当然，也可以把参数的总体积写在被调函数的返回指令的后面，让被调函数去移除参数，下面的指令就在返回主调函数前从栈中移去了24个字节：<br>
<br>
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#ffcc66">
    <tbody>
        <tr>
            <td>Ret 24</td>
        </tr>
    </tbody>
</table>
<br>
取决于被调函数的调用约定（call convention），这两种方式每次只能用一个。你还要注意的是每个线程都有自己独立的堆栈。</p>
<p align="center"> </p>
<div forimg="1"><img  src="http://hiphotos.baidu.com/page%5Freadonly/pic/item/a5589162dba5e0d8e6113a54.jpg" class="blogimg" small="0" border="0"></div>
<p> </p>
<p> </p>
<div class="right">　　<strong>C++和异常</strong> <br>
<br>
回忆一下我在第一节中介绍的EXCEPTION_REGISTRATION结构，我们曾用它向操作系统注册了发生异常时要被调用的回调函数。VC++也是这么做的，不过它扩展了这个结构<a name="baidusnap1"></a><strong style="color: black; background-color: #a0ffff;">的语义</strong>，在它的后面添加了两个新字段：</div>
<div class="right">
<table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#ffcc66">
    <tbody>
        <tr>
            <td>struct EXCEPTION_REGISTRATION <br>
            { <br>
            EXCEPTION_REGISTRATION* prev; <br>
            DWORD handler; <br>
            int id; <br>
            DWORD ebp; <br>
            };</td>
        </tr>
    </tbody>
</table>
</div>
<div class="right"><br>
VC++会为绝大部分函数③添加一个EXCEPTION_REGISTRATION类型的局部变量，它的最后一个字段（ebp）与栈桢指针指向的位置重
叠。函数的序言创建这个结构并把它注册给操作系统，尾声则恢复主调函数的EXCEPTION_REGISTRATION。id字段的意义我将在下一节介
绍。<br>
<br>
VC++编译函数时会为它生成两部分数据：<br>
<br>
a）异常回调函数 <br>
<br>
b）一个包含函数重要信息的数据结构，这些信息包括catch块、这些块的地址和这些块所关心的异常的类型等等。我把这个结构称为funcinfo，有关它的详细讨论也在下一节。 <br>
<br>
图3是考虑了异常处理之后的运行时堆栈。widget的异常回调函数位于由FS:[0]指向的异常处理链的开始位置（这是由widget的序言设置
的）。异常处理程序把widget的funcinfo结构的地址交给函数__CxxFrameHandler，__CxxFrameHandler会检查
这个结构看函数中有没有catch块对当前的异常感兴趣。如果没有的话，它就返回ExceptionContinueSearch给操作系统，于是操作系
统会从异常处理链表中取得下一个结点，并调用它的异常处理程序（也就是调用当前函数的那个函数的异常处理程序）。</div>
<div class="right">
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center">
            <div forimg="1"><img  src="http://hiphotos.baidu.com/page%5Freadonly/pic/item/3ff8c135ba4de21491ef3954.jpg" class="blogimg" small="0" border="0"></div>
            </div>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div class="right"><br>
这一过程将一直进行下去——直到处理程序找到一个能处理当前异常的catch块为止，这时它就不再返回操作系统了。但是在调用catch块之前（由于有
funcinfo结构，所以知道catch块的入口，参见图3），必须进行堆栈展开，也就是清理掉当前函数的栈桢下面的所有其他的栈桢。这个操作稍微有点
复杂，因为：异常处理程序必须找到异常发生时生存在这些栈桢上的所有局部对象，并依次调用它们的<strong style="color: white; background-color: #00aa00;">析构函数</strong>。后面我将对此进行详细介绍。 <br>
<br>
异常处理程序把这项工作委托给了各个栈桢自己的异常处理程序。从FS:[0]指向的异常处理链的第一个结点开始，它 依次调用每个结点的处理程序，告诉它堆栈正在展开。与之相呼应，这些处理程序会调用每个局部对象的<strong style="color: white; background-color: #00aa00;">析构函数</strong>，然后返回。此过程一直进行到与异常处理程序自 身相对应的那个结点为止。 <br>
<br>
由于catch块是函数的一部分，所以它使用的也是函数的栈桢。因此，在调用catch块之前，异常处理程序必须激活它所隶属的函数的栈桢。 <br>
<br>
其次，每个catch块都只接受一个参数，其类型是它希望捕获的异常的类型。异常处理程序必须把异常对象本身或者是异常对象的引用拷贝到catch块的栈
桢上，编译器在funcinfo中记录了相关信息，处理程序根据这些信息就能知道到哪去拷贝异常对象了。 <br>
<br>
拷贝完异常并激活栈桢后，处理程序将调用catch块。而catch块将把控制权下一步要转移到的地址返回来。请注意：虽然这时堆栈已经展开，栈桢也都
被清除了，但它们占据的内存空间并没有被覆盖，所有的数据都还好好的待在栈上。这是因为异常处理程序仍在执行，象其他函数一样，它也需要栈来存放自己的局
部对象，而其栈桢就位于发生异常的那个函数的栈桢的下面。catch块返回以后，异常处理程序需要&#8220;杀掉&#8221;异常对象。此后，它让ESP指向目标函数（控制
权要转移到的那个函数）的栈桢的末尾——这样就把（包括它自己的在内的）所有栈桢都删除了，然后再跳转到catch块返回的那个地址去，就胜利的完成整个
异常处理任务了。但它怎么知道目标函数的栈桢末尾在哪呢？事实上它没法知道，所以编译器把这个地址保存到了栈桢上（由前言来完成），如图3所示，栈桢指针
EBP下面第16个字节就是。 <br>
<br>
当然，catch块也可能<strong style="color: black; background-color: #ff9999;">抛出</strong>新异常，或者是将原来的异常重新<strong style="color: black; background-color: #ff9999;">抛出</strong>。处理程序必须对此有所准备。如果是<strong style="color: black; background-color: #ff9999;">抛出</strong>新异常，它必须杀掉原来的那个；而如果是重新<strong style="color: black; background-color: #ff9999;">抛出</strong>原来的异常，它必须能继续传播（propagate）这个异常。 <br>
<br>
这里我要特别强调一点：由于每个线程有自己独立的堆栈，所以每个线程也都有自己独立的、由FS:[0]指向的EXCEPTION_REGISTRATION链。</div>
</div><img src ="http://www.cppblog.com/fwxjj/aggbug/66251.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fwxjj/" target="_blank">大龙1</a> 2008-11-07 22:41 <a href="http://www.cppblog.com/fwxjj/archive/2008/11/07/66251.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>欲加速，故生并发之策，存临界不可达，故而生锁，阻塞患于锁，固又生避阻之策  ----  转</title><link>http://www.cppblog.com/fwxjj/archive/2008/11/07/66239.html</link><dc:creator>大龙1</dc:creator><author>大龙1</author><pubDate>Fri, 07 Nov 2008 13:36:00 GMT</pubDate><guid>http://www.cppblog.com/fwxjj/archive/2008/11/07/66239.html</guid><wfw:comment>http://www.cppblog.com/fwxjj/comments/66239.html</wfw:comment><comments>http://www.cppblog.com/fwxjj/archive/2008/11/07/66239.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/fwxjj/comments/commentRss/66239.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/fwxjj/services/trackbacks/66239.html</trackback:ping><description><![CDATA[欲加速，故生并发之策，存临界不可达，故而生<a name="baidusnap1"></a><strong style="color: black; background-color: #a0ffff;">锁</strong>，阻塞患于<strong style="color: black; background-color: #a0ffff;">锁</strong>，固又生避阻之策。。。
此刻主要想记录下关于并发中<strong style="color: black; background-color: #a0ffff;">锁</strong>相关的内容，当然，我也只想记录一些真正有效用的东西。
可以说<strong style="color: black; background-color: #a0ffff;">锁</strong>是衍生自并发，故谈并发必然至<strong style="color: black; background-color: #a0ffff;">锁</strong>。
此篇不欲从减少临界区以提高并发度的角度来考虑，不会深度探索诸如如何基于CAS来构建高质量无<strong style="color: black; background-color: #a0ffff;">锁</strong>数据结构等。
而是从反方向，从如何很好的运用<strong style="color: black; background-color: #a0ffff;">锁</strong>策略的角度来考虑。
这里要强调的一点是，无论如何，临界区<a name="baidusnap2"></a><strong style="color: black; background-color: #99ff99;">在</strong>一个系统中基本上是必然存<strong style="color: black; background-color: #99ff99;">在</strong>的。CAS的确可以<strong style="color: black; background-color: #99ff99;">在</strong>很多地方通过自身机制来消去<strong style="color: black; background-color: #a0ffff;">锁</strong>以达到化解临界区之目的。但是这个实现复杂度却又着实提升了，况且，也不是所有地方都能够或者值得去CAS。相比而言，<strong style="color: black; background-color: #a0ffff;">锁</strong>比较容易理解。
好了，切入主题：并发之------<strong style="color: black; background-color: #a0ffff;">锁</strong>策略!
好，首先是定界加<strong style="color: black; background-color: #a0ffff;">锁</strong>策略。
<font size="" color="#ff0000" face="">定界加<strong style="color: black; background-color: #a0ffff;">锁</strong>(Scoped Locking)：</font>能确保当控制进入到某一范围时，自动获得<strong style="color: black; background-color: #a0ffff;">锁</strong>，而当控制离开范围时，自动释放<strong style="color: black; background-color: #a0ffff;">锁</strong>，不管从该范围返回的路径是什么。
给段普通的<a name="baidusnap0"></a><strong style="color: black; background-color: #ffff66;">C++</strong>代码sample:
bool increment(const string &amp;path) {
Item *item = lookup_or_create(path);
lock.acquire();
if(entry==0){
lock.release();
return false;
} else {
entry-&gt;increment_hit_count();
lock.release();
return true;
}
}
这段代码完全可以正常工作，但是lock.acquire()和lock.release()之间存<strong style="color: black; background-color: #99ff99;">在</strong>着多路返回，如果以上情况复杂点，写代码的人不一定记得<strong style="color: black; background-color: #99ff99;">在</strong>每个返回点都释放<strong style="color: black; background-color: #a0ffff;">锁</strong>。OK, 就算情况不复杂，拿上面的例子来看，如果entry-&gt;increment_hit_count()抛出了个异常，那如何？？？很显然，<strong style="color: black; background-color: #a0ffff;">锁</strong>得不到释放了，这显然会导致其它想要得到<strong style="color: black; background-color: #a0ffff;">锁</strong>的线程永远阻塞。
那怎么样避免呢？定界加<strong style="color: black; background-color: #a0ffff;">锁</strong>模式是正用于此。
你可以定义个哨兵类(guard)类，当控制进入一个区域时，哨兵类的<a name="baidusnap3"></a><strong style="color: black; background-color: #ff9999;">构造函数</strong>自动获得一个<strong style="color: black; background-color: #a0ffff;">锁</strong>，当控制离开这个区域时，哨兵类的析构函数自动释放该<strong style="color: black; background-color: #a0ffff;">锁</strong>，因为根据<strong style="color: black; background-color: #ffff66;">C++</strong>的语义，即便<strong style="color: black; background-color: #99ff99;">在</strong>程序中抛出一个异常，析构函数还是会执行。将哨兵类实例化，以<strong style="color: black; background-color: #99ff99;">在</strong>定义临界区的方法和块区域中获得或释放<strong style="color: black; background-color: #a0ffff;">锁</strong>。类似于autoPoint的手法，需要注意的是：一，<strong style="color: black; background-color: #99ff99;">在</strong>哨兵类中要使用指向<strong style="color: black; background-color: #a0ffff;">锁</strong>的指针而不是使用栈上<strong style="color: black; background-color: #a0ffff;">锁</strong>对象，以防止对<strong style="color: black; background-color: #a0ffff;">锁</strong>的复制或赋值；二，给哨兵类增加一个owner标志，用来表示哨兵是否成功获得了<strong style="color: black; background-color: #a0ffff;">锁</strong>，该标志也可以指示当错误地使用静态/全局<strong style="color: black; background-color: #a0ffff;">锁</strong>时，由&#8220;初始化错误&#8221;而导致的失败。通过<strong style="color: black; background-color: #99ff99;">在</strong>析构函数中检查这个标志，可以避免当哨兵释放它并不拥有的<strong style="color: black; background-color: #a0ffff;">锁</strong>而产生的运行时错误。
哨兵类代码示范：
class Thread_Mutex_Gurad {
public:
Thread_Mutex_Guard(Thread_Mutex &amp;lock):lock_(&amp;lock), owner_ (false){
lock_-&gt;acquire();
owner_ = true;
}
~Thread_Mutex_Guard(){
if(owner_) lock_-&gt;release();
}
private:
Thread_Mutex *lock_;
bool owner_;
Thread_Mutex_Guard(const Thread_Mutex_Guard &amp;);
void operator=(const Thread_Mutex_Guard &amp;);
};
以上模式是基于<strong style="color: black; background-color: #ffff66;">C++</strong>的特性来玩的。<strong style="color: black; background-color: #ffff66;">C++</strong>栈对象离开作用域时，必然调用其析构，这是死规则，所以这样OK。
再拿java作下对比，如果使用synchronized关键字，OK,你不用理会上面的麻烦，JVM帮你搞定。但如果你用的是
ReentrantLock或者ReadWriteLock之类，那么，下面的写法基本上就是死规矩了。
lock.lock();
try{
} finally{
lock.unlock();
}
以上代码不能显示获取和释放<strong style="color: black; background-color: #a0ffff;">锁</strong>，你可以很简单的给它加上。
现<strong style="color: black; background-color: #99ff99;">在</strong>懒得写东西了，下文后续补上。。。。。。
java下也有个finalize方法来做实例的资源销毁，但是JVM作GC的时机不确定，并非对象离开作用域就立马调用。所以你不要拿java的<strong style="color: black; background-color: #a0ffff;">锁</strong>对豍<img src ="http://www.cppblog.com/fwxjj/aggbug/66239.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fwxjj/" target="_blank">大龙1</a> 2008-11-07 21:36 <a href="http://www.cppblog.com/fwxjj/archive/2008/11/07/66239.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++中结构体的字节对齐问题   ----   转</title><link>http://www.cppblog.com/fwxjj/archive/2008/11/05/66065.html</link><dc:creator>大龙1</dc:creator><author>大龙1</author><pubDate>Wed, 05 Nov 2008 15:30:00 GMT</pubDate><guid>http://www.cppblog.com/fwxjj/archive/2008/11/05/66065.html</guid><wfw:comment>http://www.cppblog.com/fwxjj/comments/66065.html</wfw:comment><comments>http://www.cppblog.com/fwxjj/archive/2008/11/05/66065.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/fwxjj/comments/commentRss/66065.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/fwxjj/services/trackbacks/66065.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<p>&nbsp; 前不久，在C++程序中碰到一个有关<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong><strong style="COLOR: black; BACKGROUND-COLOR: #ff9999">字节对齐</strong>的问题。</p>
<p>一。问题描述</p>
<p>在程序中,定义了一个<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>,如下:<br>typedef struct<br>{<br>&nbsp;&nbsp; char name[33];<br>&nbsp;&nbsp; int ID;<br>&nbsp;&nbsp; int&nbsp; age;<br>} PERSON;</p>
<p>声明了一个该<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>的数组:<br>PERSON peo[30];</p>
<p>当从<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>中取出ID字段给一个int类型的局部变量<a name=baidusnap2></a><strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">赋值</strong>时,却出现异常.<br>比如<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>中的字段都已经有初始值<br>peo[0].ID =4;</p>
<p>下面的<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">赋值</strong>语句<br>int tempID = peo[0].ID;<br>却不能正确得到数值4,tempID得到的是67108864.<br>经检查67108864是4在高位时的数值大小.<br><strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">赋值</strong>时本来应该是取内存中的四个Bytes:"04 00 00 00"<br>可是取值时却是用"00 00 00 04" 的方式.<br>在调试过程中,从peo[0].ID取值是正确的,得到数字4,可程序执行上面<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">赋值</strong>语句后:<br>tempID还是得到的是67108864.</p>
<p>也就是说,在调试器中取值是正确的,汇编后的程序取值却是不正确的.<br>程序在开始用了的很长一段时间并没有出现这种问题,这个问题是最近才发生的.<br>真是百思不得其解。还有一点是明确的，程序涉及到网络传输。</p>
<p>可是如果把<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>中的字符数组大小由33改为36，一切正常了！</p>
<p>原理上肯定是<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>的位对齐问题,但为什么以前编译使用没出问题,现在编译才发生呢?<br>应该怎么解决呢?</p>
<p>二。寻找问题的原因。</p>
<p>经过CSDN社区各位老大的帮助，并且自己仔细去了解程序中的编译条件部分，原则上理解了这问题的本质所在。</p>
<p>发现在网络模块中使用到了"#pram pack(1)"这样的编译条件，而其它模块则没有加入这种编译条件。</p>
<p>而CSDN中其中一个大虾是这样解释的：&#8220;对齐方式是给编译器看的，编译器根据这个来决定内存布局。一旦编译成二进制文件内存布局就已经确定了，如果两段代码对同一个结构使用的对齐方式不同，那么就会对内存里的值做出了不同的解释，<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">赋值</strong>的一方认为char[33]占了36个字节，从第37个字节填写04 00 00 00，可是读取的一方认为char[33]只有33个字节，那就从第34个字节处取四个字节当作ID。&#8221;</p>
<p>这次网友的解释，我认为指出了问题的本质所在：&#8220;如果两段代码对同一个结构使用的对齐方式不同，那么就会对内存里的值做出了不同的解释&#8221;。我们的程序给<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>初始化部分是按VC编译器中默认的<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>8<strong style="COLOR: black; BACKGROUND-COLOR: #ff9999">字节对齐</strong>，而在网络模块中，由于使用了"#pram pack(1)"，结果从<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>中取值时，编译器认为<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>是按1<strong style="COLOR: black; BACKGROUND-COLOR: #ff9999">字节对齐</strong>，最终导致了问题的产生。</p>
<p>三。解决方法</p>
<p>为了解决这个问题，就需要程序中所有的代码对同一个<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>都使用同一种对齐即可。</p>
<p>会有两种解决办法：<br>一是把网络模块中的"#pram pack(1)"去掉，<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>都是按VC编译器中默认的<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>8字节方式对齐。<br>二是设置<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">结构体</strong>按1字节方式进行对齐，程序所有模块都按这种对齐方式编译。</p>
<p>设置在VC的"project"-&gt;"setting..."-&gt;"c/c++":struct member aligment改成1 Bytes.</p>
<img src ="http://www.cppblog.com/fwxjj/aggbug/66065.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fwxjj/" target="_blank">大龙1</a> 2008-11-05 23:30 <a href="http://www.cppblog.com/fwxjj/archive/2008/11/05/66065.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在linux下实现windows查找文件和查找文件中内容的功能</title><link>http://www.cppblog.com/fwxjj/archive/2008/10/29/65468.html</link><dc:creator>大龙1</dc:creator><author>大龙1</author><pubDate>Wed, 29 Oct 2008 11:30:00 GMT</pubDate><guid>http://www.cppblog.com/fwxjj/archive/2008/10/29/65468.html</guid><wfw:comment>http://www.cppblog.com/fwxjj/comments/65468.html</wfw:comment><comments>http://www.cppblog.com/fwxjj/archive/2008/10/29/65468.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/fwxjj/comments/commentRss/65468.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/fwxjj/services/trackbacks/65468.html</trackback:ping><description><![CDATA[查找文件 == find . * | grep xxx(文件名)<br>查找内容 == find . * | xargs grep xxx(内容)<br><br><img src ="http://www.cppblog.com/fwxjj/aggbug/65468.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fwxjj/" target="_blank">大龙1</a> 2008-10-29 19:30 <a href="http://www.cppblog.com/fwxjj/archive/2008/10/29/65468.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ubuntu下mp3播放及中文乱码    -------  转</title><link>http://www.cppblog.com/fwxjj/archive/2008/10/11/63746.html</link><dc:creator>大龙1</dc:creator><author>大龙1</author><pubDate>Sat, 11 Oct 2008 09:36:00 GMT</pubDate><guid>http://www.cppblog.com/fwxjj/archive/2008/10/11/63746.html</guid><wfw:comment>http://www.cppblog.com/fwxjj/comments/63746.html</wfw:comment><comments>http://www.cppblog.com/fwxjj/archive/2008/10/11/63746.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/fwxjj/comments/commentRss/63746.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/fwxjj/services/trackbacks/63746.html</trackback:ping><description><![CDATA[<table width="100%" border="0" cellpadding="4" cellspacing="4">
    <tbody>
        <tr>
            <td class="title" align="center"><strong style="color: black; background-color: #ffff66;"><br></strong></td>
        </tr>
        <tr>
            <td align="center"><br></td>
        </tr>
        <tr>
            <td>
            <table style="table-layout: fixed;" width="100%" border="0" cellpadding="2" cellspacing="2">
                <tbody>
                    <tr>
                        <td class="message" id="zoom">1，<strong style="color: black; background-color: #a0ffff;">mp3</strong>播放<br>
                        安装gstreamer<br>
                        <br>
                        在终端输入 sudo apt-get install gstreamer0.10-fluendo-<strong style="color: black; background-color: #a0ffff;">mp3</strong><br>
                        <br>
                        安装之后mplayer正常播放<strong style="color: black; background-color: #a0ffff;">mp3</strong><br>
                        <br>
                        系统的Rhythmbox可以正常的添加文件和播放<strong style="color: black; background-color: #a0ffff;">mp3</strong><br>
                        <br>
                        2，<strong style="color: black; background-color: #a0ffff;">mp3</strong>乱码解决办法<br>
                        安装：apt-get install python-mutagen<br>
                        <br>
                        装完了以后用下面这个命令处理一下就可以了：<br>
                        mid3iconv -e gbk 文件名<br>
                        <br>
                        这个文件名可以直接把文件拖到终端里，可以同时拖多个文件。</td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table><img src ="http://www.cppblog.com/fwxjj/aggbug/63746.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fwxjj/" target="_blank">大龙1</a> 2008-10-11 17:36 <a href="http://www.cppblog.com/fwxjj/archive/2008/10/11/63746.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ubuntu默认root密码是什么？</title><link>http://www.cppblog.com/fwxjj/archive/2008/10/10/63606.html</link><dc:creator>大龙1</dc:creator><author>大龙1</author><pubDate>Thu, 09 Oct 2008 18:17:00 GMT</pubDate><guid>http://www.cppblog.com/fwxjj/archive/2008/10/10/63606.html</guid><wfw:comment>http://www.cppblog.com/fwxjj/comments/63606.html</wfw:comment><comments>http://www.cppblog.com/fwxjj/archive/2008/10/10/63606.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/fwxjj/comments/commentRss/63606.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/fwxjj/services/trackbacks/63606.html</trackback:ping><description><![CDATA[没有默认的，因为你还没给root设置密码，，你第一个 user 是在 admin 组 ，所以他可以给 root 设置密码 , so<br>
<br>
sudo passwd root <br>
[sudo] password for you ：---&gt; 输入你的密码，不回显 <br>
Enter new UNIX password: --- &gt; 设置root 密码 <br>
Retype new UNIX password: --&gt; 重复<img src ="http://www.cppblog.com/fwxjj/aggbug/63606.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fwxjj/" target="_blank">大龙1</a> 2008-10-10 02:17 <a href="http://www.cppblog.com/fwxjj/archive/2008/10/10/63606.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mount命令</title><link>http://www.cppblog.com/fwxjj/archive/2008/10/10/63605.html</link><dc:creator>大龙1</dc:creator><author>大龙1</author><pubDate>Thu, 09 Oct 2008 18:16:00 GMT</pubDate><guid>http://www.cppblog.com/fwxjj/archive/2008/10/10/63605.html</guid><wfw:comment>http://www.cppblog.com/fwxjj/comments/63605.html</wfw:comment><comments>http://www.cppblog.com/fwxjj/archive/2008/10/10/63605.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/fwxjj/comments/commentRss/63605.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/fwxjj/services/trackbacks/63605.html</trackback:ping><description><![CDATA[<span class="content"><strong style="color: black; background-color: #ffff66;">mount</strong>&nbsp; </span><span class="content">-t vfat</span><span class="content">/dev/hda5 /mnt/win<br> </span><span class="content"><strong style="color: black; background-color: #ffff66;">mount</strong> -t vfat -o iocharset=cp936 /dev/hda5 /mnt/win(显示中文<br> </span><span class="content">卸除的命令为 umoun，若是卸除上述分区，只要输入&#8220;umount /mnt/win&#8221;即可。<br> <br> </span><span class="content">　　另外，我们还可以让 Linux 在启动时自动加载分区，这样就不用每次使用 Windows 分区时都要输入命令加载了。<br><br>
首先请以 root 用户登陆，进入图形界面后通过 Linux 的文件管理器找到 /etc 目录下的 fstab
文件，单击右键选择一个文字编辑软件打开此文件，在内容的最下方添加一行命令&#8220;/dev/hda5 /mnt/win vfat
codepage=936,iocharset=cp936 1 1&#8221;，然后在 /mnt 目录下建立 win 文件夹，重新启动计算机后，再访问
/mnt/win 目录就是 Windows 分区的内容了。您也可以通过此种方法加载多个分区，而编辑时也可以在命令行方式下使用 vi 等编辑器。<br> <br> <br> iso<br> </span><font face="腩戾,verdana, arial, helvetica">mkdir /mnt/iso<br> <strong style="color: black; background-color: #ffff66;">mount</strong> -t iso9660 -o loop *.iso /mnt/iso<br> <br> <br> </font>在使用<strong style="color: black; background-color: #ffff66;">mount</strong>这个指令时，至少要先知道下列三种信息：&nbsp; <br> 　1.&nbsp;要<strong style="color: black; background-color: #ffff66;">Mount</strong>对象的文件系统类型？&nbsp;(File&nbsp;system&nbsp;type)&nbsp; <br> 　&nbsp;2.&nbsp;要<strong style="color: black; background-color: #ffff66;">Mount</strong>对象的设备名称？&nbsp;(/dev/????)&nbsp; <br> 　&nbsp;3.&nbsp;要将设备<strong style="color: black; background-color: #ffff66;">Mount</strong>到哪个目录去？&nbsp; <br> <br> 一、获得系统支持的文件系统类型&nbsp; <br> 就第一点来说，用户可以执行&nbsp; <br> 　　&nbsp;cat&nbsp;/proc/filesystems&nbsp; <br> 　Win95/98常用的FAT&nbsp;32文件系统&nbsp;：vfat&nbsp; <br> 　Win&nbsp;NT用的文件系统&nbsp;　　　　：ntfs&nbsp; <br> 　OS2用的文件系统&nbsp;　　　：hpfs&nbsp; <br> 　Linux用的文件系统&nbsp;　　　：ext2&nbsp; <br> 　光盘片用的文件系统&nbsp;　　　：iso9660&nbsp; <br> 其中虽然vfat是指FAT&nbsp;32系统，但事实上它也兼容FAT&nbsp;16的文件系统类型。<br> 二、确定设备的名称&nbsp; <br> 在Linux中，设备名称通常都在/dev里。这些设备名称的命名都是有规则的，我们可以用"推理"的方式把设备名称找出来。&nbsp; <br>
譬如说/dev/hda1这个IDE设备。hd是Hard&nbsp;Disk(硬盘)的意思，sd是SCSI&nbsp;Device，fd是
Floppy&nbsp;Device(或是Floppy&nbsp;Disk?)。a则是代表第一个设备，通常IDE接口可以接上四个IDE设备(例如四块硬盘)。所以要识
别IDE硬盘的方法分别就&nbsp; <br> 是：hda、hdb、hdc、hdd。此外，hda1中的"1"代表hda的第一个硬盘分区&nbsp; <br> (partition)，hda2代表hda的第二个分割区，依此类推。&nbsp; <br> 此外，你可以直接检查/var/log/messages这个文件，在该文件中可以找到计算机开机后，系统已辨认出来的设备代号。 <br> 三、查找挂接点&nbsp; <br> 最后我们要决定将设备挂接到哪里，先查看一下你的计算机是不是有个/mnt的空目录？该目录就是专门用来当作挂载点(<strong style="color: black; background-color: #ffff66;">Mount</strong>&nbsp;Point)的 目录。建议您在/mnt里多建这几个目录：/mnt/cdrom、/mnt/floppy、/mnt/mo等来当作目录的专用挂载点。&nbsp; <br> <br> 举例而言，如要挂载下列五个设备的话，其执行指令可能是&nbsp;(假设都是Linux&nbsp; <br> 的ext2系统，如果是Win&nbsp;XX的话，请将ext2改成vfat)：&nbsp; <br> 1.&nbsp;软盘&nbsp;===&gt;<strong style="color: black; background-color: #ffff66;">mount</strong>&nbsp;-t&nbsp;ext2&nbsp;/dev/fd0&nbsp;/mnt/floppy&nbsp; <br> 2.&nbsp;MO&nbsp;===&gt;<strong style="color: black; background-color: #ffff66;">mount</strong>&nbsp;-t&nbsp;ext2&nbsp;/dev/sda&nbsp;/mnt/mo&nbsp; <br> 3.&nbsp;cdrom&nbsp;===&gt;<strong style="color: black; background-color: #ffff66;">mount</strong>&nbsp;-t&nbsp;ext2&nbsp;/dev/hdc&nbsp;/mnt/cdrom&nbsp; <br> 4.&nbsp;SCSI&nbsp;cdrom&nbsp;===&gt;<strong style="color: black; background-color: #ffff66;">mount</strong>&nbsp;-t&nbsp;iso9660&nbsp;/dev/sdb&nbsp;/mnt/scdrom&nbsp; <br> 5.&nbsp;SCSI&nbsp;cdr&nbsp;===&gt;<strong style="color: black; background-color: #ffff66;">mount</strong>&nbsp;-t&nbsp;iso9660&nbsp;/dev/sdc&nbsp;/mnt/scdr&nbsp; <br> <br> 这是假设，如果你的设备的名称跟这个不同的话请自行修改。&nbsp; <br> <br> 最后需要注意的是：&nbsp; <br> 1.&nbsp;执行<strong style="color: black; background-color: #ffff66;">mount</strong>动作时先打一下pwd看看现在的目录是不是在挂载点，如果现在目录在挂载点的话，<strong style="color: black; background-color: #ffff66;">mount</strong>&nbsp;(或umount)不会成功&nbsp;(会显示device&nbsp;busy)。&nbsp; <br> 2.&nbsp;想卸载某设备的语法是umount&nbsp;目录名，例如umount&nbsp;/mnt/cdrom等。 <img src ="http://www.cppblog.com/fwxjj/aggbug/63605.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/fwxjj/" target="_blank">大龙1</a> 2008-10-10 02:16 <a href="http://www.cppblog.com/fwxjj/archive/2008/10/10/63605.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>