﻿<?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/lshain/category/17166.html</link><description>Beyond this world...</description><language>zh-cn</language><lastBuildDate>Thu, 26 Apr 2012 06:53:41 GMT</lastBuildDate><pubDate>Thu, 26 Apr 2012 06:53:41 GMT</pubDate><ttl>60</ttl><item><title>容易忽略的问题</title><link>http://www.cppblog.com/lshain/articles/161268.html</link><dc:creator>Lshain</dc:creator><author>Lshain</author><pubDate>Thu, 01 Dec 2011 02:24:00 GMT</pubDate><guid>http://www.cppblog.com/lshain/articles/161268.html</guid><description><![CDATA[<p>1.<br />#include&lt;cstdio&gt;</p>
<p>int main(int argc, char* argv[], char* env[])<br />{<br />&nbsp;&nbsp;&nbsp;int t = 1;<br />&nbsp;&nbsp;&nbsp;/** 32位寄存器 左右移32位 指令无效*/<br />&nbsp;&nbsp;&nbsp;printf("%d\n", t&lt;&lt;32);<br />&nbsp;&nbsp;&nbsp;printf("%d\n", t&gt;&gt;32);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;/** 注意指针类型sizeof = 4, 结构体数组指针更容易忽略*/<br />&nbsp;&nbsp;&nbsp;char* p1 = "123";<br />&nbsp;&nbsp;&nbsp;char&nbsp; p2[] = "12345";<br />&nbsp;&nbsp;&nbsp;char&nbsp; p3[10] = "1234567";<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;printf("sizeof(p1) = %d\n", sizeof(p1));<br />&nbsp;&nbsp;&nbsp;printf("sizeof(p2) = %d\n", sizeof(p2));<br />&nbsp;&nbsp;&nbsp;printf("sizeof(p3) = %d\n", sizeof(p3));<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;getchar();<br />&nbsp;&nbsp;&nbsp;return 0;<br />}<br /></p><img src ="http://www.cppblog.com/lshain/aggbug/161268.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lshain/" target="_blank">Lshain</a> 2011-12-01 10:24 <a href="http://www.cppblog.com/lshain/articles/161268.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>三字符组</title><link>http://www.cppblog.com/lshain/articles/161102.html</link><dc:creator>Lshain</dc:creator><author>Lshain</author><pubDate>Tue, 29 Nov 2011 02:06:00 GMT</pubDate><guid>http://www.cppblog.com/lshain/articles/161102.html</guid><description><![CDATA[<h1><strong><span style="font-family: 宋体; font-size: 12pt; font-weight: normal">转自<a href="http://www.cppblog.com/cc/archive/2006/07/30/10709.html"><span style="font-size: 12pt">http://www.cppblog.com/cc/archive/2006/07/30/10709.html</span></a><br />三字符组</span> </strong><strong><span style="font-family: 'Times New Roman'; font-size: 18pt; font-weight: normal">(</span> </strong><strong><span style="font-family: 宋体; font-size: 18pt; font-weight: normal">三字符序列</span> </strong><strong><span style="font-family: 'Times New Roman'; font-size: 18pt; font-weight: normal">)</span> </strong><span style="font-size: 18pt"></span></h1>
<p style="text-indent: 42.4pt"><span style="font-family: 宋体; font-size: 14pt; text-shadow: none">首先我们来看两段简单的程序，如果你不进行编译运行</span> <span style="font-size: 14pt; text-shadow: none">,</span> <span style="font-family: 宋体; font-size: 14pt; text-shadow: none">猜一猜结果分别是多少？</span> </p>
<p style="text-align: center; text-indent: 28.5pt" align="center"><strong><span style="font-family: 宋体; font-size: 14pt; text-shadow: none">程序一<br /></span></strong><strong></strong></p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><span style="color: #008080">&nbsp;1</span>&nbsp;<span style="color: #000000">#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">iostream</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;2</span>&nbsp;<span style="color: #000000">#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">iomanip</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;3</span>&nbsp;<span style="color: #0000ff">using</span>&nbsp;<span style="color: #0000ff">namespace</span><span style="color: #000000">&nbsp;std;<br /></span><span style="color: #008080">&nbsp;4</span>&nbsp;<span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;5</span>&nbsp;<span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;main()<br /></span><span style="color: #008080">&nbsp;6</span>&nbsp;<span style="color: #000000">{<br /></span><span style="color: #008080">&nbsp;7</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;x</span><span style="color: #000000">=</span><span style="color: #000000">1</span><span style="color: #000000">;<br /></span><span style="color: #008080">&nbsp;8</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;结果是多少&nbsp;?递增?????/</span><span style="color: #008000"><br /></span><span style="color: #008080">&nbsp;9</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">++</span><span style="color: #000000">x;<br /></span><span style="color: #008080">10</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">x</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">endl;<br /></span><span style="color: #008080">11</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span>&nbsp;<span style="color: #000000">0</span><span style="color: #000000">;<br /></span><span style="color: #008080">12</span>&nbsp;<span style="color: #000000">}<br /></span><span style="color: #008080">13</span>&nbsp;</div>&nbsp; <br /><span style="font-family: 宋体; color: black; font-size: 10.5pt"><strong>程序二<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><span style="color: #008080">&nbsp;1</span>&nbsp;<span style="color: #000000">#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">iostream</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;2</span>&nbsp;<span style="color: #000000">#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">iomanip</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;3</span>&nbsp;<span style="color: #0000ff">using</span>&nbsp;<span style="color: #0000ff">namespace</span><span style="color: #000000">&nbsp;std;<br /></span><span style="color: #008080">&nbsp;4</span>&nbsp;<span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;5</span>&nbsp;<span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;main()<br /></span><span style="color: #008080">&nbsp;6</span>&nbsp;<span style="color: #000000">{<br /></span><span style="color: #008080">&nbsp;7</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;x</span><span style="color: #000000">=</span><span style="color: #000000">1</span><span style="color: #000000">;<br /></span><span style="color: #008080">&nbsp;8</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;结果是多少&nbsp;?递增?????/</span><span style="color: #008000"><br /></span><span style="color: #008080">&nbsp;9</span>&nbsp;<span style="color: #000000"><br /></span><span style="color: #008080">10</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">++</span><span style="color: #000000">x;<br /></span><span style="color: #008080">11</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">x</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">endl;<br /></span><span style="color: #008080">12</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span>&nbsp;<span style="color: #000000">0</span><span style="color: #000000">;<br /></span><span style="color: #008080">13</span>&nbsp;<span style="color: #000000">}<br /></span><span style="color: #008080">14</span>&nbsp;</div></strong></span><br />
<p style="text-indent: 28.5pt"><span style="font-family: 宋体; font-size: 12pt; text-shadow: none">你猜出运行结果了么？现在我们就来揭示谜底，第一个程序的结果是</span><strong><span style="color: blue; font-size: 12pt; text-shadow: none">1,</span></strong><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">第二个程序的运行结果是</span><strong><span style="color: blue; font-size: 12pt; text-shadow: none">2</span></strong><strong></strong><strong><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">。</span></strong><strong></strong></p>
<p style="text-indent: 28.5pt"><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">哈哈，你或许会不解吧，这里就是我们需要讲的&#8220;</span><span style="font-family: 宋体; color: blue; font-size: 12pt; text-shadow: none">三字符组</span><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">&#8221;</span><span style="color: windowtext; font-size: 12pt; text-shadow: none">,</span><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">也叫着&#8220;</span><strong><span style="font-family: 宋体; color: blue; font-size: 12pt; text-shadow: none">三字符序列</span></strong><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">&#8221;。</span></p>
<p style="text-indent: 28.5pt">&nbsp;</p>
<p style="text-indent: 28.5pt"><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">三字符序列不太常见，但</span><span style="color: windowtext; font-size: 12pt; text-shadow: none">C++</span><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">标准允许把某些字符指定为三字符序列。三字符序列就是用于表示另一个字符的三个字符序列。以前为了表示键盘上没有的字符，这是必不可少的一种方法。</span></p>
<p style="text-indent: 28.5pt">&nbsp;</p>
<p style="text-indent: 28.5pt">&nbsp;</p>
<p style="text-indent: 28.5pt"><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">具体的三字符序列转义的对应关系如下表：<br /></span></p>
<div align="center">
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; border-top: medium none; border-right: medium none" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="border-bottom: green 0.75pt solid; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 55.8pt; padding-right: 5.4pt; border-top: green 1.5pt solid; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="74">
<p><strong><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">字符串</span></strong><strong></strong></p></td>
<td style="border-bottom: green 0.75pt solid; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 91.8pt; padding-right: 5.4pt; border-top: green 1.5pt solid; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="122">
<p><strong><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">转义后的含义</span></strong><strong></strong></p></td></tr>
<tr>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 55.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="74">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">??=</span></p></td>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 91.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="122">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">#</span></p></td></tr>
<tr>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 55.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="74">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">??(</span></p></td>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 91.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="122">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">[</span></p></td></tr>
<tr>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 55.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="74">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">??)</span></p></td>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 91.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="122">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">]</span></p></td></tr>
<tr>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 55.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="74">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">??/</span></p></td>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 91.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="122">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">\</span></p></td></tr>
<tr>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 55.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="74">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">??&lt;</span></p></td>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 91.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="122">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">{</span></p></td></tr>
<tr>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 55.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="74">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">??&gt;</span></p></td>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 91.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="122">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">}</span></p></td></tr>
<tr>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 55.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="74">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">??'</span></p></td>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 91.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="122">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">^</span></p></td></tr>
<tr>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 55.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="74">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">??!</span></p></td>
<td style="border-bottom: #d4d0c8; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 91.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="122">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">|</span></p></td></tr>
<tr>
<td style="border-bottom: green 1.5pt solid; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 55.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="74">
<p><span style="color: windowtext; font-size: 12pt; text-shadow: none">??-</span></p></td>
<td style="border-bottom: green 1.5pt solid; border-left: #d4d0c8; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 91.8pt; padding-right: 5.4pt; border-top: #d4d0c8; border-right: #d4d0c8; padding-top: 0cm" valign="top" width="122">
<p><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">～</span></p></td></tr></tbody></table><br /><br />
<p style="text-indent: 28.5pt"><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">我们现在已经基本知道什么是三字符组了，那么我们在来分析一下前面遇到的程序。</span></p>
<p style="text-indent: 28.5pt">&nbsp;<span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">程序</span><span style="color: windowtext; font-size: 12pt; text-shadow: none">1中,</span><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">在第8行，那是一行注释，</span><span style="color: windowtext; font-size: 12pt; text-shadow: none">//</span><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">让后面的部分编程注释，但是问题就在这里了，</span><strong><span style="color: blue; font-size: 12pt; text-shadow: none">??/</span></strong><span style="font-family: 宋体; color: blue; font-size: 12pt; text-shadow: none">，</span><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">这其实就是一个三字符组了，前面两个</span><strong></strong><strong><span style="color: blue; font-size: 12pt; text-shadow: none">??</span></strong><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">就意味着这里后面就会发生转义。这个程序中，&#8220;</span><strong><span style="color: blue; font-size: 12pt; text-shadow: none">??/</span></strong><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">&#8221;就会被转义成&#8220;</span><span style="color: blue; font-size: 12pt; text-shadow: none">\</span><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">&#8221;</span><span style="color: windowtext; font-size: 12pt; text-shadow: none">,&nbsp;&nbsp; </span><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">而把这个符号放在一行的末尾就相当于将接下来的一行粘贴到这一行的末尾，所以本程序中的&#8220;</span><span style="color: blue; font-size: 12pt; text-shadow: none">++x</span><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">&#8221;也就成了注释的一部分，那么我们的结果是</span><strong><span style="color: blue; font-size: 12pt; text-shadow: none">1</span></strong><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">就不足为奇了，而第二个程序的三字符组后面跟的是一行空白，所以不影响到下面的一行代码，&#8220;</span><span style="color: blue; font-size: 12pt; text-shadow: none">++x</span><span style="font-family: 宋体; color: windowtext; font-size: 12pt; text-shadow: none">&#8221;照常执行，所以结果就是</span><strong><span style="color: blue; font-size: 12pt; text-shadow: none">2</span></strong><strong><span style="font-family: 宋体; font-size: 12pt; text-shadow: none">。</span></strong><strong></strong></p>
<p style="text-indent: 28.5pt"><strong><span style="font-size: 12pt; text-shadow: none"><br /></span></strong><span style="font-family: 宋体; font-size: 12pt; text-shadow: none"><br />此文完。<br />参考自《</span><span style="font-size: 12pt; text-shadow: none">Exceptional C++ style</span><span style="font-family: 宋体; font-size: 12pt; text-shadow: none">中文版</span><span style="font-size: 12pt; text-shadow: none">/Herb Sutter</span><span style="font-family: 宋体; font-size: 12pt; text-shadow: none">著》</span></p></div><img src ="http://www.cppblog.com/lshain/aggbug/161102.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lshain/" target="_blank">Lshain</a> 2011-11-29 10:06 <a href="http://www.cppblog.com/lshain/articles/161102.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>9个故事</title><link>http://www.cppblog.com/lshain/articles/156039.html</link><dc:creator>Lshain</dc:creator><author>Lshain</author><pubDate>Sat, 17 Sep 2011 10:03:00 GMT</pubDate><guid>http://www.cppblog.com/lshain/articles/156039.html</guid><wfw:comment>http://www.cppblog.com/lshain/comments/156039.html</wfw:comment><comments>http://www.cppblog.com/lshain/articles/156039.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lshain/comments/commentRss/156039.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lshain/services/trackbacks/156039.html</trackback:ping><description><![CDATA[<p align="right">&nbsp;</p>
<p>一、女浴室起火，里面人乱作一团，赤身往外跑，只见大街上白花花一大群，一老者大喊"快捂住"，众裸女突然醒悟，但身上要紧部位有三处，手忙脚乱捂不过来，不知所措。这时老者又大喊："捂脸就行，下面都一样！" </p>
<p>【此事的重要启示：在特殊情况下抓工作不可能面面俱到，要抓住重点。】</p>
<p>二、某日,女秘书神色凝重地说：王总,我怀孕了。 王继续低头看文件,然后淡淡一笑:我早结扎了。 女秘书楞了一会媚笑道:我和您开玩笑呢! 王抬起头看了她一眼，喝了口茶说:我也是。<br />【此事的重要启示：在江湖上混的人,遇事不要慌,先让子弹飞一会。】</p>
<p>三、男子去提亲，女方家长：请自我介绍。<br />A说：我有一千万；<br />B说：我有一栋豪宅，价值两千万；<br />家长很满意。就问C，你家有什么？<br />C答：我什么都没有，只有一个孩子，在你女儿肚子里。<br />AB无语，走了。<br />【此事的重要启示：核心竞争力不是钱和房子，是在关键的岗位有自已的人。】</p>
<p>四、7年前他为了出国抛弃了未婚妻，现在事业有成，他开始愧疚，听说她过的不好，他想去弥补。<br />他去到了她的鱼摊，她在刮鳞，边上蹲着一个男娃，模样有几分像他，他心里一震。<br />她突然停下，指着隔壁摊的男人：你咋还不给孩子做饭呢！他松了口气，转身走了。<br />她递根烟给隔壁摊男人：刚才不好意思<br />【 不愿意做你的累赘 不愿意让你带着愧疚过一身 】</p>
<p><br />五、父亲在洗车, 儿子拿起小石头在车门上划起来. <br />父亲见此大怒, 拿起扳手就打了下去, <br />后来儿子被送到医院, 证实手指骨折. <br />面对父亲, 儿子轻声说道: 爸爸, 手指会好的, 不要担心了. <br />父亲内心无比自责. 一怒之下, <br />冲回去要把自己的汽车给砸了. 他看见儿子划的痕迹: <br />爸爸, 我爱你.<br />【 有些事是否在看清之后再做决定更好呢 】</p>
<p><br />六、草原上有对狮子母子。小狮子问母狮子："妈，幸福在哪里？"母狮子说："幸福就在你的尾巴上。"<br />于是小狮子不断追着尾巴跑，但始终咬不到。母狮子笑道："傻瓜！幸福不是这样得到的！只要你昂首向前走，幸福就会一直跟随着你！"。 </p>
<p>【 刻意的追寻 不如勇敢的往前走 成功又有多远呢 】</p>
<p><br />七、有一个盲了的女孩，她一无所有，只剩下她男朋友，男朋友问她："如果你眼睛好了，能和我结婚吗？"女孩答应了。<br />很快，女孩可以移植新视角膜，也很快回复视力，但她发现她男朋友也是盲的。男朋友向她求婚，女孩拒绝了，最后男孩只说了一句话:"take care of my eyes."<br />【 照顾好我的眼睛 】</p>
<p><br />八、他向她求婚时，只说了三个字：相信我；<br />她为他生下第一个女儿的时候，他对她说：辛苦了；<br />女儿出嫁那天，他搂着她的肩说：还有我；<br />他收到她病危的那天，重复的对她说：我在这；<br />她要走的那一刻，他亲吻她的额头轻声说：你等我。<br />这一生，他没有对他说过一次"我爱你"，但爱，从未离开过。 </p>
<p>【 这个世界有不会表白的人 但谁说他们一定缺少爱 】</p>
<p><br />九、儿子养不起年迈的母亲，决定把她背上山丢下去。傍晚，儿子说要背母亲上山走走，母亲吃力地爬上他的背。<br />他一路都在想爬高点再丢下她，当看到母亲在他背上偷偷往路上洒豆子，他很生气地问："你洒豆子干什么？"结果母亲的回答让他泪流满面："傻儿子，我怕你等会儿一个人下山会迷路。" <br />【 父母的爱伴随着你一生 哪怕他们已经年迈 】<br />这九个故事是我转载的，拜读完以后我感触良多，转来跟朋友们共享。故事也许不只是故事，内中蕴含着大道理，只要我们善于感悟，就一定会受益无穷的。求顶！！<br /></p>
<p align="right">&nbsp;</p><img src ="http://www.cppblog.com/lshain/aggbug/156039.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lshain/" target="_blank">Lshain</a> 2011-09-17 18:03 <a href="http://www.cppblog.com/lshain/articles/156039.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>函数指针(注意)</title><link>http://www.cppblog.com/lshain/articles/152445.html</link><dc:creator>Lshain</dc:creator><author>Lshain</author><pubDate>Thu, 04 Aug 2011 07:41:00 GMT</pubDate><guid>http://www.cppblog.com/lshain/articles/152445.html</guid><description><![CDATA[转自 《C++Primer4th第四版中文版》 p373-p374<br />1.返回指向函数的指针<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;函数可以返回指向函数的指针，但是，正确写出这种返回类型相当不容易：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ff is a function taking an int and returning a function pointer<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// the function pointed to returns an int and takes an int* and an int<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int (*ff(int))(int*, int);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;阅读函数指针声明的最佳方法是从声明的名字开始由里而外理解。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;要理解该声明的含义，首先观察：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ff(int)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将 ff 声明为一个函数，它带有一个 int 型的形参。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;该函数返回 int (*)(int*, int);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;它是一个指向函数的指针，所指向的函数返回 int 型并带有两个分别是int* 型和 int 型的形参。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: red">使用 typedef 可使该定义更简明易懂：</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// PF is a pointer to a function returning an int, taking an int* and an int<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef int (*PF)(int*, int);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PF ff(int); // ff returns a pointer to function<br /><br />2.允许将形参定义为函数类型，但函数的返回类型则必须是指向函数的指针，而不能是函数。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;具有函数类型的形参所对应的实参将被自动转换为指向相应函数类型的指针。但是，当返回的是函数时，同样的转换操作则无法实现：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// func is a function type, not a pointer to function!<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef int func(int*, int);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void f1(func);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ok: f1 has a parameter of function type<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;func f2(int);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// error: f2 has a return type of function type<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;func *f3(int);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ok: f3 returns a pointer to function type<br /><br />3.指向重载函数的指针<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C++ 语言允许使用函数指针指向重载的函数：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;extern void ff(vector&lt;double&gt;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;extern void ff(unsigned int);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// which function does pf1 refer to?<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void (*pf1)(unsigned int) = &amp;ff;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ff(unsigned)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;指针的类型必须与重载函数的一个版本精确匹配。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果没有精确匹配的函数，则对该指针的初始化或赋值都将导致编译错误：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void (*pf2)(int) = &amp;ff;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// error: no match: invalid parameter list<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;double (*pf3)(vector&lt;double&gt;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pf3 = &amp;ff;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// error: no match: invalid return type<br /> <img src ="http://www.cppblog.com/lshain/aggbug/152445.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lshain/" target="_blank">Lshain</a> 2011-08-04 15:41 <a href="http://www.cppblog.com/lshain/articles/152445.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OpenOffice 3.0编译环境搭建记录（转）</title><link>http://www.cppblog.com/lshain/articles/152337.html</link><dc:creator>Lshain</dc:creator><author>Lshain</author><pubDate>Wed, 03 Aug 2011 03:59:00 GMT</pubDate><guid>http://www.cppblog.com/lshain/articles/152337.html</guid><description><![CDATA[<p><strong>转自<a href="http://blog.163.com/facteur@126/blog/static/23208030200902011921609/">http://blog.163.com/facteur@126/blog/static/23208030200902011921609/</a><br />第〇步：</strong>这篇日志主要参考了如下内容，如有任何问题，请前往如下地址：</p>
<p><a href="http://wiki.services.openoffice.org/wiki/Building_OOo_with_Cygwin_on_Windows"><font color="#ee790b">http://wiki.services.openoffice.org/wiki/Building_OOo_with_Cygwin_on_Windows</font></a></p>
<p><strong>第一步：</strong>安装Cygwin，安装的时候不要采用默认安装（default），要采用（标准安装），安装之后将如下几个符号链接改成拷贝文件：awk.exe、gunzip.exe、tar.exe</p>
<p><strong>第二步：</strong>在有网络的环境下下载并安装附加的Perl模块</p>
<p>在CygWin环境下使用如下命令启动Perl命令行交互窗口：</p>
<p>perl -MCPAN -e shell</p>
<p>使用如下命令安装Perl模块：</p>
<p>install $MODULENAME</p>
<p>需要安装的Perl模块如下：</p>
<p>&nbsp;&nbsp;&nbsp; *&nbsp; Archive::Zip<br />&nbsp;&nbsp;&nbsp; * XML::Parser (though it seems that this is already installed; doesn't hurt to do it)<br />&nbsp;&nbsp;&nbsp; * URI<br />&nbsp;&nbsp;&nbsp; * LWP::UserAgent<br />&nbsp;&nbsp;&nbsp; * SOAP::Lite<br />&nbsp;&nbsp;&nbsp; * Crypt::SSLeay </p>
<p><strong>第三步</strong>：安装JDK，要选择1.4.2或者1.5版，1.6版是不行的</p>
<p><strong>第四步：</strong>安装ant</p>
<p>下载apache-ant-1.7.1-bin.zip，解压缩到C:\anthome目录。</p>
<p><strong>第五步：</strong>安装VC2008 Express Edition</p>
<p>安装文件是VS2008ExpressWithSP1ENUX1504728.iso</p>
<p><strong>第六步：</strong>安装Microsoft SDKs</p>
<p>安装文件是6.0.6001.18000.367-KRMSDK_EN.iso</p>
<p><strong>第七步：</strong>更改系统设置</p>
<p>在&#8220;控制面板&#8221;&#8212;&#8212;&#8220;区域和语言选项&#8221;对话框中，将&#8220;区域选项&#8221;选项卡中的&#8220;标准和格式&#8221;由&#8220;中文（中国）&#8221;更改为&#8220;英语（美国）&#8221;，将&#8220;位置&#8221;由&#8220;中国&#8221;更改为&#8220;美国&#8221;；将&#8220;高级&#8221;选项卡中&#8220;非Unicode程序的语言&#8221;由&#8220;中文（中国）&#8221;更改为&#8220;英语（美国）&#8221;。</p>
<p>这一步是必须做的，如果漏掉此步骤，编译时会报很多错误！</p>
<p><strong>第八步：</strong>获取并解压缩源代码</p>
<p>从官方网站下载源代码，包括如下几个文件：</p>
<ul><li>OOo_3.0.0_src_binfilter.tar.bz2</li><li>OOo_3.0.0_src_core.tar.bz2</li><li>OOo_3.0.0_src_extensions.tar.bz2</li><li>OOo_3.0.0_src_l10n.tar.bz2</li><li>OOo_3.0.0_src_system.tar.bz2</li></ul>
<p>在CygWin环境下用 &#8220;for file in *.bz2; do tar jxvf ${file}; done&#8221; 命令解压缩源代码包，注意此步骤如果使用XP上的WinRAR软件解压缩据说会有问题！</p>
<p>另外下载mozilla-source-1.7.5.tar.bz2，放到OOO300_m9\moz\download目录下。</p>
<p><strong>第九步：</strong>下载并拷贝附加文件到相应的目录，这一步需要注意：有几个dll文件在下载的时候是exe文件，其实是个压缩包，执行一下就能解压出来！</p>
<ul><li>gdiplus.dll -----&gt; external/gdiplus</li><li>unicows.dll -----&gt; external/unicows</li><li>dbghelp.dll -----&gt; external/dbghelp</li><li>instmsiw.exe and instmsia.exe -----&gt; external/msi</li><li>for 2005 compiler: msvcp80.dll and msvcr80.dll -----&gt; external/msvcp80</li><li>for 2008 compiler (until DEV300 m22): msvcp90.dll and msvcr90.dll -----&gt; external/msvcp90</li><li>for 2008 compiler starting with DEV300m23: Microsoft_VC90_CRT_x86.msm and</li><li>policy_9_0_Microsoft_VC90_CRT_x86.msm -----&gt; external/msm90</li><li>GPC -----&gt; Unpack to external/gpc</li><li>Mozilla binary distribution(WNTMSCIruntime.zip,WNTMSCIlib.zip,WNTMSCIinc.zip) -----&gt; moz/zipped</li><li>msvcr71.dll and msvcp71.dll -----&gt; external/msvcp71</li></ul>
<p><strong>第十步：</strong>建立编译环境</p>
<p>这一步遇到一个问题是总说几个.msm的文件没有找到，需要拷贝的相应的目录去，但是拷贝之后还是报这个错儿，最后发现configure文件中检测这几个文件要求是可执行权限（&#8220;-x&#8221;），但是在CygWin下面查看的时候这几个文件都没有执行权限，chmod也加不上，只好修改configure将检测条件改为&#8220;-e&#8221;，顺利通过configure。这一步使用的configure参数如下：</p>
<p>./configure \<br />&nbsp;--disable-directx \<br />&nbsp;--with-cl-home=/cygdrive/c/Program\ Files/Microsoft\ Visual\ Studio\ 9.0/VC \<br />&nbsp;--disable-activex \<br />&nbsp;--disable-atl \<br />&nbsp;--disable-build-mozilla \<br />&nbsp;--with-frame-home=/cygdrive/c/Program\ Files/Microsoft\ SDKs/Windows/v6.1/ \<br />&nbsp;--with-psdk-home=/cygdrive/c/Program\ Files/Microsoft\ SDKs/Windows/v6.1/ \<br />&nbsp;--with-midl-path=/cygdrive/c/Program\ Files/Microsoft\ SDKs/Windows/v6.1/Bin/ \<br />&nbsp;--with-asm-home=/cygdrive/c/Program\ Files/Microsoft\ Visual\ Studio\ 9.0/VC \<br />&nbsp;--with-jdk-home=/cygdrive/c/Program\ Files/Java/jdk1.5.0_17/ \<br />&nbsp;--with-ant-home=/cygdrive/c/anthome/ \<br />&nbsp;--with-csc-path=/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v3.5 \<br />&nbsp;--with-use-shell=bash \<br />&nbsp;--with-lang="en-US zh-CN zh-TW"</p>
<p><strong>第十一步：</strong>在SRC_ROOT目录执行./bootstrap建立dmake工具</p>
<p><strong>第十二步：</strong>设置环境变量，这些环境变量都是configure的时候检测好的，在SRC_ROOT目录执行&#8220;source winenv.set.sh&#8221;即可</p>
<p><strong>第十三步：</strong>开始编译，在SRC_ROOT/instsetoo_native目录执行&#8220;build --all -P4&#8221;</p>
<p>后记：按照以上步骤，编译可顺利通过！</p><img src ="http://www.cppblog.com/lshain/aggbug/152337.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lshain/" target="_blank">Lshain</a> 2011-08-03 11:59 <a href="http://www.cppblog.com/lshain/articles/152337.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++标准库简介</title><link>http://www.cppblog.com/lshain/articles/149642.html</link><dc:creator>Lshain</dc:creator><author>Lshain</author><pubDate>Tue, 28 Jun 2011 03:46:00 GMT</pubDate><guid>http://www.cppblog.com/lshain/articles/149642.html</guid><description><![CDATA[<p style="text-align: left" align="left"><span style="font-family: 宋体; font-size: 12pt" lang="EN-US">(转载自<a href="http://kom118.blog.163.com/blog/static/4766731820102115261864/">http://kom118.blog.163.com/blog/static/4766731820102115261864/</a>)<br />&nbsp;&nbsp;&nbsp;C++标准库的所有头文件都没有扩展名。<br />&nbsp;&nbsp;&nbsp;C++标准库的内容总共在50个标准头文件中定义，其中18个提供了C库的功能。&lt;cname&gt;形式的标准头文件&nbsp;[ &lt;complex&gt;例外 ] 其内容与ISO标准C包含的name.h头文件相同，但容纳了C++扩展的功能。在&lt;cname&gt;形式标准的头文件中，与宏相关的名称在全局作用域中定义，其他名称在std命名空间中声明。在C++中还可以使用name.h 形式的标准C库头文件名。<br />&nbsp;&nbsp;&nbsp;C++标准库的内容分为10类：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C1.语言支持&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C2.输入/输出&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C3.诊断&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C4.一般工具&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C5.字符串<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C6.容器&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C7.迭代器支持&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C8.算法&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C9.数值操作&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C10.本地化<br /><br />&nbsp;&nbsp;&nbsp;C1标准库中包含语言支持功能相关的头文件<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cstddef&gt; 定义宏NULL和offsetof，以及其他标准类型size_t和ptrdiff_t。与对应的标准C头文件的区别是，NULL是C++空指针常量的补充定义，宏offsetof接受结构或者联合类型参数，只要他们没有成员指针类型的非静态成员即可。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;limits&gt; 提供与基本数据类型相关的定义。例如，对于每个数值数据类型，它定义了可以表示出来的最大值和最小值以及二进制数字的位数。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;climits&gt; 提供与基本整数数据类型相关的C样式定义。这些信息的C++样式定义在 &lt;limits&gt;中<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cfloat&gt; 提供与基本浮点型数据类型相关的C样式定义。这些信息的C++样式定义在 &lt;limits&gt;中<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cstdlib&gt; 提供支持程序启动和终止的宏和函数。这个头文件还声明了许多其他杂项函数，例如搜索和排序函数，从字符串转换为数值等函数。它与对应的标准C头文件stdlib.h不同，定义了abort(void)。abort()函数还有额外的功能，它不为静态或自动对象调用析构函数，也不调用传给 atexit()函数的函数。它还定义了exit()函数的额外功能，可以释放静态对象，以注册的逆序调用用atexit()注册的函数。清除并关闭所有 打开的C流，把控制权返回给主机环境。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;new&gt; 支持动态内存分配<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;typeinfo&gt; 支持变量在运行期间的类型标识<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;exception&gt; 支持异常处理，这是处理程序中可能发生的错误的一种方式<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cstdarg&gt; 支持接受数量可变的参数的函数。即在调用函数时，可以给函数传送数量不等的数据项。它定义了宏va_arg、va_end、va_start以及va_list类型<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;csetjmp&gt; 为C样式的非本地跳跃提供函数。这些函数在C++中不常用<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;csignal&gt; 为中断处理提供C样式支持</p>
<p>&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;C2 支持流输入/输出的头文件&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;iostream&gt; 支持标准流cin、cout、cerr和clog的输入和输出，它还支持多字节字符标准流wcin、wcout、wcerr和wclog。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;iomanip&gt; 提供操纵程序，允许改变流的状态，从而改变输出的格式。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ios&gt; 定义iostream的基类<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;istream&gt; 为管理输出流缓存区的输入定义模板类<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ostream&gt; 为管理输出流缓存区的输出定义模板类<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;sstream&gt; 支持字符串的流输入输出<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;fstream&gt; 支持文件的流输入输出<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;iosfwd&gt; 为输入输出对象提供向前的声明<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;streambuf&gt; 支持流输入和输出的缓存<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cstdio&gt; 为标准流提供C样式的输入和输出<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cwchar&gt; 支持多字节字符的C样式输入输出</p>
<p><br />&nbsp;&nbsp;&nbsp;C3 与诊断功能相关的头文件&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;stdexcept&gt; 定义标准异常。异常是处理错误的方式<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cassert&gt; 定义断言宏，用于检查运行期间的情形<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cerrno&gt; 支持C样式的错误信息</p>
<p>&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;C4 定义工具函数的头文件&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;utility&gt; 定义重载的关系运算符，简化关系运算符的写入，它还定义了pair类型，该类型是一种模板类型，可以存储一对值。这些功能在库的其他地方使用<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;functional&gt; 定义了许多函数对象类型和支持函数对象的功能，函数对象是支持operator()()函数调用运算符的任意对象<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;memory&gt; 给容器、管理内存的函数和auto_ptr模板类定义标准内存分配器<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ctime&gt; 支持系统时钟函数</p>
<p><br />&nbsp;&nbsp;&nbsp;C5 支持字符串处理的头文件&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;string&gt; 为字符串类型提供支持和定义，包括单字节字符串(由char组成)的string和多字节字符串(由wchar_t组成)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cctype&gt; 单字节字符类别<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cwctype&gt; 多字节字符类别<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cstring&gt; 为处理非空字节序列和内存块提供函数。这不同于对应的标准C库头文件，几个C样式字符串的一般C库函数被返回值为const和非const的函数对替代了<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cwchar&gt; 为处理、执行I/O和转换多字节字符序列提供函数，这不同于对应的标准C库头文件，几个多字节C样式字符串操作的一般C库函数被返回值为const和非const的函数对替代了。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cstdlib&gt; 为把单字节字符串转换为数值、在多字节字符和多字节字符串之间转换提供函数</p>
<p><br />&nbsp;&nbsp;&nbsp;C6 定义容器类的模板的头文件&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;vector&gt; 定义vector序列模板，这是一个大小可以重新设置的数组类型，比普通数组更安全、更灵活<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt; 定义list序列模板，这是一个序列的链表，常常在任意位置插入和删除元素<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;deque&gt; 定义deque序列模板，支持在开始和结尾的高效插入和删除操作<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;queue&gt; 为队列(先进先出)数据结构定义序列适配器queue和priority_queue<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;stack&gt; 为堆栈(后进先出)数据结构定义序列适配器stack<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;map&gt; map是一个关联容器类型，允许根据键值是唯一的，且按照升序存储。multimap类似于map，但键不是唯一的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;set&gt; set是一个关联容器类型，用于以升序方式存储唯一值。multiset类似于set，但是值不必是唯一的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bitset&gt; 为固定长度的位序列定义bitset模板，它可以看作固定长度的紧凑型bool数组</p>
<p><br />&nbsp;&nbsp;&nbsp;C7 支持迭代器的头文件&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;iterator&gt; 给迭代器提供定义和支持</p>
<p><br />&nbsp;&nbsp;&nbsp;C8 有关算法的头文件&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;algorithm&gt; 提供一组基于算法的函数，包括置换、排序、合并和搜索<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cstdlib&gt; 声明C标准库函数bsearch()和qsort()，进行搜索和排序<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ciso646&gt; 允许在代码中使用and代替&amp;&amp;</p>
<p><br />&nbsp;&nbsp;&nbsp;C9 有关数值操作的头文件&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;complex&gt; 支持复杂数值的定义和操作<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;valarray&gt; 支持数值矢量的操作<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;numeric&gt; 在数值序列上定义一组一般数学操作，例如accumulate和inner_product<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cmath&gt; 这是C数学库，其中还附加了重载函数，以支持C++约定<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;cstdlib&gt; 提供的函数可以提取整数的绝对值，对整数进行取余数操作</p>
<p>&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;C10 有关本地化的头文件&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;locale&gt; 提供的本地化包括字符类别、排序序列以及货币和日期表示。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;clocale&gt; 对本地化提供C样式支持<br />&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;C++标准库很大。非常大。难以置信的大。怎么个大法？这么说吧：在C++标准中，关于标准库的规格说明占了密密麻麻300多页，这还不包括标准C库，后者只是 "作为参考"（老实说，原文就是用的这个词）包含在C++库中。 </p>
<p>　 当然，并非总是越大越好，但在现在的情况下，确实越大越好，因为大的库会包含大量的功能。标准库中的功能越多，开发自己的应用程序时能借助的功能就越多。C++库并非提供了一切（很明显的是，没有提供并发和图形用户接口的支持），但确实提供了很多。几乎任何事你都可以求助于它。 </p>
<p>　 在归纳标准库中有些什么之前，需要介绍一下它是如何组织的。因为标准库中东西如此之多，你（或象你一样的其他什么人）所选择的类名或函数名就很有可能和标准库中的某个名字相同。为了避免这种情况所造成的名字冲突，实际上标准库中的一切都被放在名字空间std中（参见条款28）。但这带来了一个新问题。无数现有的C++代码都依赖于使用了多年的伪标准库中的功能，例如，声明在&lt;iostream.h&gt;，&lt;complex.h&gt;, &lt;limits.h&gt;等头文件中的功能。现有软件没有针对使用名字空间而进行设计，如果用std来包装标准库导致现有代码不能用，将是一种可耻行为。（这种釜底抽薪的做法会让现有代码的程序员说出比 "可耻" 更难听的话） </p>
<p>&nbsp;&nbsp;&nbsp;慑于被激怒的程序员会产生的破坏力，标准委员会决定为包装了std的那部分标准库构件创建新的头文件名。生成新头文件的方法仅仅是将现有C++头文件名中的.h去掉，方法本身不重要，正如最后产生的结果不一致也并不重要一样。所以&lt;iostream.h&gt;变成了&lt;iostream&gt;，&lt;complex.h&gt;变成了&lt;complex&gt;，等等。对于C头文件，采用同样的方法，但在每个名字前还要添加一个c。所以C的&lt;string.h&gt;变成了&lt;cstring&gt;，&lt;stdio.h&gt;变成了&lt;cstdio&gt;，等等。最后一点是，旧的C++头文件是官方所反对使用的（即，明确列出不再支持），但旧的C头文件则没有（以保持对C的兼容性）。实际上，编译器制造商不会停止对客户现有软件提供支持，所以可以预计，旧的C++头文件在未来几年内还是会被支持。所以，实际来说，下面是C++头文件的现状： </p>
<p>&nbsp;&nbsp;&nbsp;&#183; 旧的C++头文件名如&lt;iostream.h&gt;将会继续被支持，尽管它们不在官方标准中。这些头文件的内容不在名字空间std中。 </p>
<p>&nbsp;&nbsp;&nbsp;&#183; 新的C++头文件如&lt;iostream&gt;包含的基本功能和对应的旧头文件相同，但头文件的内容在名字空间std中。（在标准化的过程中，库中有些部分的细节被修改了，所以旧头文件和新头文件中的实体不一定完全对应。） </p>
<p>&nbsp;&nbsp;&nbsp;&#183; 标准C头文件如&lt;stdio.h&gt;继续被支持。头文件的内容不在std中。 </p>
<p>&nbsp;&nbsp;&nbsp;&#183; 具有C库功能的新C++头文件具有如&lt;cstdio&gt;这样的名字。它们提供的内容和相应的旧C头文件相同，只是内容在std中。 </p>
<p>&nbsp;&nbsp;&nbsp;所有这些初看有点怪，但不难习惯它。最大的挑战是把字符串头文件理清楚：&lt;string.h&gt;是旧的C头文件，对应的是基于char*的字符串处理函数；&lt;string&gt;是包装了std的C++头文件，对应的是新的string类（看下文）；&lt;cstring&gt;是对应于旧C头文件的std版本。如果能掌握这些（我相信你能），其余的也就容易了。 </p>
<p>&nbsp;&nbsp;&nbsp;关于标准库，需要知道的第二点是，库中的一切几乎都是模板。看看你的老朋友iostream。（如果你和iostream不是朋友，转到条款2，看看你为什么要和它发展关系）iostream帮助你操作字符流，但什么是字符？是char吗？是wchar_t？是Unicode字符？一些其它的多字节字符？没有明显正确的答案，所以标准库让你去选。所有的流类（stream class）实际上是类模板，在实例化流类的时候指定字符类型。例如，标准库将cout类型定义为ostream，但ostream实际上是一个basic_ostream&lt;char&gt;类型定义（typedef）。 </p>
<p>&nbsp;&nbsp;&nbsp;类似的考虑适用于标准库中其它大部分类。string不是类，它是类模板：类型参数限定了每个string类中的字符类型。complex不是类，它是类模板：类型参数限定了每个complex 类中实数部分和虚数部分的类型。vector不是类，它是类模板。如此不停地进行下去。 </p>
<p>&nbsp;&nbsp;&nbsp;在标准库中你无法避开模板，但如果只是习惯于和char类型的流和字符串打交道，通常可以忽略它们。这是因为，对这些组件的char实例，标准库都为它们定义了typedef，这样你就可以在编程时继续使用cin，cout，cerr等对象，以及istream，ostream，string等类型，不必担心cin的真实类型是basic_istream&lt;char&gt;以及string的真实类型是basic_string&lt;char&gt;。 </p>
<p>&nbsp;&nbsp;&nbsp;标准库中很多组件的模板化和上面所建议的大不相同。再看看那个概念上似乎很直观的string。当然，可以基于"它所包含的字符类型"确定它的参数，但不同的字符集在细节上有不同，例如，特殊的文件结束字符，拷贝它们的数组的最有效方式，等等。这些特征在标准中被称为traits，它们在string实例中通过另外一个模板参数指定。此外，string对象要执行动态内存分配和释放，但完成这一任务有很多不同的方法（参见条款10）。哪 一个最好？你得选择：string模板有一个Allocator参数，Allocator类型的对象被用来分配和释放string对象所使用的内存。 </p>
<p>&nbsp;&nbsp;&nbsp;这里有一个basic_string模板的完整声明，以及建立在它之上的string类型定义（typedef）；你可以在&lt;string&gt;头文件中找到它（或与之相当的什么东西）： </p>
<p>&nbsp;&nbsp;&nbsp;namespace std{ </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;template&lt;class charT, class traits = char_traits&lt;charT&gt;, class Allocator = allocator&lt;charT&gt; &gt;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class basic_string; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef basic_string&lt;char&gt; string; </p>
<p>&nbsp;&nbsp;&nbsp;}</p>
<p><br />&nbsp;&nbsp;&nbsp;注意，basic_string的traits和Allocator参数有缺省值。这在标准库中是很典型的做法。它为使用者提供了灵活性， 但对于这种灵活性所带来的复杂性，那些只想做 "正常" 操作的"典型" 用户却又可以避开。换句话说，如果只想使用象C字符串那样的字符串对象，就可以使用string对象，而不用在意实际上是在用 basic_string&lt;char, char_traits&lt;char&gt;, allocator&lt;char&gt; &gt;类型的对象。 </p>
<p>&nbsp;&nbsp;&nbsp;是的，通常可以这么做，但有时还是得稍稍看看底层。例如，条款34指出，声明一个类而不提供定义具有优点；它还指出，下面是一种声明string类型的错误方法： </p>
<p>&nbsp;&nbsp;&nbsp;class string; // 会通过编译，但你不会这么做 </p>
<p>&nbsp;&nbsp;&nbsp;先不要考虑名字空间，这里真正的问题在于：string不是一个类，而是一个typedef。如果可以通过下面的方法解决问题就太好了： </p>
<p>&nbsp;&nbsp;&nbsp;typedef basic_string&lt;char&gt; string; </p>
<p>&nbsp;&nbsp;&nbsp;但这又不能通过编译。"你所说的basic_string是什么东西？"编译器会奇怪---当然，它可能会用不同的语句来问你。所以，为了声明string，首先得声明它所依赖的所有模板。如果可以这么做的话，就会象下面这样： </p>
<p>&nbsp;&nbsp;&nbsp;template&lt;class charT&gt; struct char_traits; </p>
<p>&nbsp;&nbsp;&nbsp;template&lt;class T&gt; class allocator; </p>
<p>&nbsp;&nbsp;&nbsp;template&lt;class charT, class traits = char_traits&lt;charT&gt;, class Allocator = allocator&lt;charT&gt; &gt;&nbsp;<br />&nbsp;&nbsp;&nbsp;class basic_string; </p>
<p>&nbsp;&nbsp;&nbsp;typedef basic_string&lt;char&gt; string;</p>
<p><br />&nbsp;&nbsp;&nbsp;然而，你不能声明string。至少不应该。这是因为，标准库的实现者声明的stirng（或std名字空间中任何其它东西）可以和标准中所指定的有所 不同，只要最终提供的行为符合标准就行。例如，basic_string的实现可以增加第四个模板参数，但这个参数的缺省值所产生的代码的行为要和标准中 所说的原始的basic_string一致。 </p>
<p>&nbsp;&nbsp;&nbsp;那到底该怎么办？不要手工声明string（或标准库中其它任何部分）。相反，只用包含一个适当的头文件，如&lt;string&gt;。 </p>
<p>&nbsp;&nbsp;&nbsp;有了头文件和模板的这些知识，现在可以看看标准C++库中有哪些主要组件： </p>
<p>&nbsp;&nbsp;&nbsp;&#183; 标准C库。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;它还在，你还可以用它。虽然有些地方有点小的修修补补，但无论怎么说，还是那个用了多年的C库。 </p>
<p>&nbsp;&nbsp;&nbsp;&#183; Iostream。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;和 "传统" Iostream的实现相比，它已经被模板化了，继承层次结构也做了修改，增强了抛出异常的能力，可以支持string（通过stringstream 类）和国际化（通过locales ---- 见下文）。当然，你期望Iostream库所具有的东西几乎全都继续存在。也就是说，它还是支持流缓冲区，格式化标识符，操作子和文件，还有 cin，cout，cerr和clog对象。这意味着可以把string和文件当做流，还可以对流的行为进行更广泛的控制，包括缓冲和格式化。 </p>
<p>&nbsp;&nbsp;&nbsp;&#183; String。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string对象在大多数应用中被用来消除对char*指针的使用。它们支持你所期望的那些操作（例如，字符串连接，通过 operator[]对单个字符进行常量时间级的访问，等等），它们可以转换成char*，以保持和现有代码的兼容性，它们还自动处理内存管理。一些 string的实现采用了引用计数（参见条款M29），这会带来比基于char*的字符串更佳的性能（时间和空间上）。 </p>
<p>&nbsp;&nbsp;&nbsp;&#183; 容器。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不要再写你自己的基本容器类！标准库提供了下列高效的实现：vector（就象动态可扩充的数组），list（双链表），queue， stack，deque，map，set和bitset。唉，竟然没有hash table（虽然很多制造商作为扩充提供），但多少可以作为补偿的一点是， string是容器。这很重要，因为它意味着对容器所做的任何操作（见下文）对string也适用。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;什么？你不明白我为什么说标准库的实现很高效？很简单：标准库规定了每个类的接口，而且每条接口规范中的一部分是一套性能保证。所以，举例来说，无论vector是如何实现的，仅仅提供对它的元素的访问是不够的，还必须提供 "常量时间" 内的访问。如果不这样，就不是一个有效的vector实现。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;很多 C++程序中，动态分配字符串和数组导致大量使用new和delete，new/delete错误 ---- 尤其是没有delete掉new出来的内存而导致的泄漏 ---- 时常发生。如果使用string和vector对象（二者都执行自身的内存管理）而不使用char*和动态分配的数组的指针，很多new和delete就 可以免于使用，使用它们所带来的问题也会随之消失（例如，条款6和11）。 </p>
<p>&nbsp;&nbsp;&nbsp;&#183; 算法。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;标准容器当然好，如果存在易于使用它们的方法就更好。标准库就提供了大量简易的方法（即，预定义函数，官方称为算法(algorithm) ---- 实际上是函数模板），其中的大多数适用于库中所有的容器 ---- 以及内建数组（built-in arrays）！ </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;算法将容器的内容当作序列（sequence），每个算法可以应用于一个容器中所有值所对应的序列，或者一个子序列（subsequence）。标准算 法有for_each（为序列中的每个元素调用某个函数），find（在序列中查找包含某个值的第一个位置 ---- 条款M35展示了它的实现），count_if（计算序列中使得某个判定为真的所有元素的数量），equal（确定两个序列包含的元素的值是否完全相 同），search（在一个序列中找出某个子序列的起始位置），copy（拷贝一个序列到另一个），unique（在序列中删除重复 值），rotate（旋转序列中的值），sort（对序列中的值排序）。注意这里只是抽取了所有算法中的几个；标准库中还包括其它很多算法。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;和容器操作一样，算法也有性能保证。例如，stable_sort算法执行时要求不超过0比较级(N log N) 。（如果不理解上面句子中符号 "0" 的意思，不要紧张。概括的说，它的意思实际上是，stable_sort提供的性能必须和最高效的通用排序算法在同一个级别。） </p>
<p>&nbsp;&nbsp;&nbsp;&#183; 对国际化的支持。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不同的文化以不同的方式行事。和C库一样，C++库提供了很多特性有助于开发出国际化的软件。但虽然从概念上来说和C类似，其实C++的方法还是有所不同。例如，C++为支持国际化广泛使用了模板，还利用了继承和虚函数，这些一定不会让你感到奇怪。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;支持国际化最主要的构件是facets和locales。facets描述的是对一种文化要处理哪些特性，包括排序规则（即，某地区字符集中的字符应该 如何排序），日期和时间应该如何表示，数字和货币值应该如何表示，怎样将信息标识符映射成（自然的）明确的语言信息，等等。locales将多组 facets捆绑在一起。例如，一个关于美国的locale将包括很多facets，描述如何对美国英语字符串排序，如何以适合美国人的方式读写日期和时 间，读写货币和数字值，等等。而对于一个关于法国的locales来说，它描述的是怎么以法国人所习惯的方式完成这些任务。C++允许单个程序中同时存在 多个locales，所以一个应用中的不同部分可能采用的是不同的规范。 </p>
<p>&nbsp;&nbsp;&nbsp;&#183; 对数字处理的支持。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FORTRAN的末日可能就快到了。C++库为复数类（实数和虚数部分的精度可以是float，double或long double）和专门针对数值编程而设计的特殊数组提供了模板。例如，valarray类型的对象可用来保存可以任意混叠(aliasing)的元素。这 使得编译器可以更充分地进行优化，尤其是对矢量计算机来说。标准库还对两种不同类型的数组片提供了支持，并提供了算法计算内积(inner product)，部分和(partial sum)，临差(adjacent difference)等。 </p>
<p>&nbsp;&nbsp;&nbsp;&#183; 诊断支持。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;标准库支持三种报错方式：C的断言（参见条款7），错误号，例外。为了有助于为例外类型提供某种结构，标准库定义了下面的例外类（exception class）层次结构： </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|---domain_error&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|----- logic_error&lt;---- |---invalid_argument&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;||---length_error&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;||---out_of_range&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exception&lt;--|&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;||--- range_error&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|-----runtime_error&lt;--|---underflow_error&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|---overflow_error </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logic_error（或它的子类）类型的例外表示的是软件中的逻辑错误。理论上来说，这样的错误可以通过更仔细的程序设计来防止。runtime_error（或它的子类）类型的例外表示的是只有在运行时才能发现的错误。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;可以就这样使用它们，可以通过继承它们来创建自己的例外类，或者可以不去管它。没有人强迫你使用它。 </p>
<p>&nbsp;&nbsp;&nbsp;上面列出的内容并没有涵盖标准库中的一切。记住，规范有300多页。但它还是为你初步展现了标准库的基本概貌。 </p>
<p>&nbsp;&nbsp;&nbsp;标准库中容器和算法这部分一般称为标准模板库（STL---- 参见条款M35）。STL中实际上还有第三个构件 ---- 迭代子（Iterator） ---- 前面没有介绍过。迭代子是指针似的对象，它让STL算法和容器共同工作。不过现在不需要弄清楚迭代子，因为我这里所介绍的是标准库的高层描述。如果你对它 感兴趣，可以在条款39和M35中找到使用它的例子。 </p>
<p>&nbsp;&nbsp;&nbsp;STL是标准库中最具创新的部分，这并不是因为它提供了容器和算法（虽然它们非常有用），而是因为它的体系结构。简单来说，它的体系结构具有扩展性：你可以对STL进行添加。当然，标准库中的组件本身是固定的，但如果遵循STL构建的规范，你可以写出自己的容器，算法和迭代子，使它们可以和标准STL组件一起工作，就象标准组件自身之间相互工作一样。你还可以利用别人所写的符合STL规范的容器，算法和迭代子，就象别人利用你的一样。使得STL具有创新意义的原因在于它实际上不是软件，而是一套规范（convention）。标准库中的STL组件只是具体体现了遵循这种规范所能带来的好处。 </p>
<p>&nbsp;&nbsp;&nbsp;通过使用标准库中的组件，通常可以让你避免从头到尾来设计自己的IO流，string，容器，国际化，数值数据结构以及诊断等机制。这就给了你更多的时间和精力去关注软件开发中真正重要的部分：实现那些有别于你的竞争对手的软件功能。<br /></p>
<p style="text-align: left" align="left"></span>&nbsp;</p> <img src ="http://www.cppblog.com/lshain/aggbug/149642.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lshain/" target="_blank">Lshain</a> 2011-06-28 11:46 <a href="http://www.cppblog.com/lshain/articles/149642.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员的十层楼(转载)-文章作者:周伟明</title><link>http://www.cppblog.com/lshain/articles/149272.html</link><dc:creator>Lshain</dc:creator><author>Lshain</author><pubDate>Thu, 23 Jun 2011 06:44:00 GMT</pubDate><guid>http://www.cppblog.com/lshain/articles/149272.html</guid><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 自西方文艺复兴以来，中国在自然科学方面落后西方很多，软件领域也不例外。当然现在中国的许多程序员们对此可能有许多不同的意见，有些人认为中国的程序员水平远落后于西方，有些则认为中国的程序员个人能力并不比西方的程序员差，只是整个软件产业落后而已。</p>
<p>那么，到底中国的程序员水平比西方程序员水平差，还是中国有许多优秀的程序员达到或超过了西方程序员同等水平呢？要解决这个问题，必须先知道程序员有多少种技术层级，每个层级需要什么样的技术水平，然后再比较中国和西方在各个技术层级的人数，就可以知道到底有没有差距，差距有多大。</p>
<p>当然，对于如何划分程序员的技术层级，不同公司或不同人会有不同的划分标准，下面的划分仅代表个人的观点，如有不当之处，还请砸板砖予以纠正。</p>
<p><span id="more-812"></span><strong>第1层&nbsp; 菜鸟</strong></p>
<p>第1层楼属于地板层，迈进这层楼的门槛是很低的。基本上懂计算机的基本操作，了解计算机专业的一些基础知识，掌握一门基本的编程语言如C/C++，或者Java，或者JavaScript，...，均可入门迈进这层。</p>
<p>在这层上，中国有着绝对的优势，除了从计算机专业毕业的众多人数外，还有大量的通信、自动化、数学等相关专业的人士进入这一行，此外还有众多的其他专业转行的人士，人数绝对比西方多出甚多。并且还有一个优势就是我们这层人员的平均智商比西方肯定高。</p>
<p>没有多少人愿意一辈子做菜鸟，因为做"菜鸟"的滋味实在是不咋的，整天被老大们吆喝着去装装机器，搭建一下测试环境，或者对照着别人写好的测试用例做一些黑盒测试，好一点的可以被安排去写一点测试代码。当然如果运气"好"的话，碰到了国内的一些作坊式的公司，也有机会去写一些正式的代码。</p>
<p>所以，菜鸟们总是在努力学习，希望爬更高的一层楼去。</p>
<p><strong>第2层 大虾</strong></p>
<p>从第1层爬到第2层相对容易一些，以C/C++程序员为例，只要熟练掌握C/C++编程语言，掌握C标准库和常用的各种数据结构算法，掌握STL的基本实现和使用方法，掌握多线程编程基础知识，掌握一种开发环境，再对各种操作系统的API都去使用一下，搞网络编程的当然对socket编程要好好掌握一下，然后再学习一些面向对象的设计知识和设计模式等，学习一些测试、软件工程和质量控制的基本知识，大部分人经过2～3年的努力，都可以爬到第2层，晋升为"大虾"。</p>
<p>中国的"大虾"数量和"菜鸟"数量估计不会少多少，所以这层上仍然远领先于西方。</p>
<p>大虾们通常还是有些自知之明，知道自己只能实现一些简单的功能，做不了大的东西，有时候还会遇到一些疑难问题给卡住，所以他们对那些大牛级的人物通常是非常崇拜的，国外的如Robert C. Martin、Linus Torvalds，国内的如求伯君、王志东等通常是他们崇拜的对象。其中的有些人希望有一天也能达到这些大牛级人物的水平，所以他们继续往楼上爬去。</p>
<p><strong>第3层 牛人</strong></p>
<p>由于"大虾"们经常被一些疑难问题给卡住，所以有了"大虾"们只好继续学习，他们需要将原来所学的知识进一步熟练掌握，比如以熟练掌握C++编程语言为例，除了学一些基础性的C++书籍如《C++ Primer》，《Effective C++》，《Think in C++》，《Exception C++》等之外，更重要的是需要了解C++编译器的原理和实现机制，了解操作系统中的内部机制如内存管理、进程和线程的管理机制，了解处理器的基础知识和代码优化的方法，此外还需要更深入地学习更多的数据结构与算法，掌握更深入的测试和调试知识以及质量管理和控制方法，对各种设计方法有更好的理解等。</p>
<p>学习上面说的这些知识不是一挥而就的，不看个三五十本书并掌握它是做不到的。以数据结构算法来说，至少要看个5～10本这方面的著作；以软件设计来说，光懂结构化设计、面向对象设计和一些设计模式是不够的，还要了解软件架构设计、交互设计、面向方面的设计、面向使用的设计、面向数据结构算法的设计、情感化设计等，否则是很难进到这个楼层的。</p>
<p>当然除了上面说的知识外，大虾们还需要去学习各种经验和技巧。当然这点难不倒他们，现在出版的书籍众多，网络上的技术文章更是不胜数，然后再去各种专业论坛里泡一泡，把这些书籍和文章中的各种经验、技能、技巧掌握下来，再去学习一些知名的开源项目如Apache或Linux操作系统的源代码实现等。此时对付一般的疑难问题通常都不在话下，菜鸟和大虾们会觉得你很"牛"，你也就爬到了第3层，晋升为"牛人"了。</p>
<p>看了上面所讲的要求，可能有些大虾要晕过去了，成为牛人要学这么多东西啊！要求是不是太高了？其实要求一点也不高，这么点东西都掌握不了的话，怎么能让别人觉得你"牛"呢？</p>
<p>需要提一下的是，进入多核时代后，从第2层爬到第3层增加了一道多核编程的门槛。当然要迈过这道门槛并不难，已经有很多前辈高人迈进了这道门槛，只要循着他们的足迹前进就可以了。</p>
<p>在国内，一旦成为"牛人"，通常可以到许多知名的公司里去，运气好者可以挂上一个架构师的头衔，甚至挂上一个"首席架构师"或者"首席xx学家"的头衔也不足为奇。有不少爬到这层的人就以为到了楼顶了，可以眼睛往天上看了，开始目空一切起来，以为自己什么都可以做了，什么都懂了，经常在网络上乱砸板砖是这个群体的最好写照。由此也看出，国内的牛人数量仍然众多，远多于西方的牛人数量，在这层上仍然是领先的。</p>
<p>也有不少谦虚的"牛人"，知道自己现在还不到半桶水阶段。他们深知爬楼的游戏就像猴子上树一样，往下看是笑脸，往上看是屁股。为了多看笑脸，少看屁股，他们并没有在此停步不前，而是继续寻找到更上一层的楼梯，以便继续往上爬。</p>
<p><strong>第4层 大牛</strong></p>
<p>从第3层爬到第4层可不像上面说过的那几层一样容易，要成为大牛的话，你必须要能做牛人们做不了的事情，解决牛人们解决不了问题。比如牛人们通常都不懂写操作系统，不会写编译器，不懂得TCP/IP协议的底层实现，如果你有能力将其中的任何一个实现得象模象样的话，那么你就从牛人升级为"大牛"了。</p>
<p>当然，由于各个专业领域的差别，这里举操作系统、编译器、TCP/IP协议只是作为例子，并不代表成为"大牛"一定需要掌握这些知识，以时下热门的多核编程来说，如果你能比牛人们更深入地掌握其中的各种思想原理，能更加自如的运用，并有能力去实现一个象开源项目TBB库一样的东西，也可以成为"大牛"，又或者你能写出一个类似Apache一样的服务器，或者写出一个数据库，都可以成为"大牛"。</p>
<p>要成为"大牛"并不是一件简单的事情，需要付出比牛人们多得多的努力，一般来说，至少要看过200~400本左右的专业书籍并好好掌握它，除此之外，还得经常关注网络和期刊杂志上的各种最新信息。</p>
<p>当"牛人"晋升为"大牛"，让"牛人们"发现有比他们更牛的人时，对"牛人"们的心灵的震撼是可想而知的。由于牛人们的数量庞大，并且牛人对大虾和菜鸟阶层有言传身教的影响，所以大牛们通常能获得非常高的社会知名度，几乎可以用"引无数菜鸟、大虾、牛人竞折腰"来形容，看看前面提过的Linus Torvalds等大牛，应该知道此言不虚。</p>
<p>虽然成为"大牛"的条件看起来似乎很高似的，但是这层楼并不是很难爬的一层，只要通过一定的努力，素质不是很差，还是有许多"牛人"可以爬到这一层的。由此可知，"大牛"这个楼层的人数其实并不像想像的那么少，例如比尔&#183;盖茨之类的人好像也是属于这一层的。</p>
<p>由于"大牛"这层的人数不少，所以也很难统计除到底是中国的"大牛"数量多还是西方的大牛数量多？我估计应该是个旗鼓相当的数量，或者中国的"大牛"们会更多一些。</p>
<p>看到这里，可能会有很多人会以为我在这里说瞎话，Linus Torvalds写出了著名的Linux操作系统，我国并没有人写出过类似的东西啊，我国的"大牛"怎么能和西方的比呢? 不知大家注意到没有，Linus Torvalds只是写出了一个"象模象样"的操作系统雏形，Linux后来真正发展成闻名全球的开源操作系统期间，完全是因为许多支持开源的商业公司如 IBM等，派出了许多比Linus Torvalds更高楼层的幕后英雄在里面把它开发出来的。</p>
<p>可能有些菜鸟认为Linus Torvalds是程序员中的上帝，不妨说个小故事：</p>
<p>Linus，Richard Stallman和Don Knuth（高德纳）一同参加一个会议。</p>
<p>Linus 说："上帝说我创造了世界上最优秀的操作系统。"</p>
<p>Richard Stallman自然不甘示弱地说："上帝说我创造了世界上最好用的编译器。"</p>
<p>Don Knuth一脸疑惑的说："等等，等等，我什么时候说过这些话？"</p>
<p>由此可以看出，Linus Torvalds的技术水平并不像想像中那么高，只是"牛人"和"大虾"觉得"大牛"比他们更牛吧了。在我国，有一些当时还处于"大虾"层的人物，也能写出介绍如何写操作系统的书，并且书写得非常出色，而且写出了一个有那么一点点象模象样的操作系统来。我想中国的"大牛"们是不会比西方差的，之所以没有人写出类似的商业产品来，完全是社会环境的原因，并不是技术能力达不到的原因。</p>
<p>"大牛"们之所以成为大牛，主要的原因是因为把"牛人"给盖了下去，并不是他们自己觉得如何牛。也许有很多菜鸟、大虾甚至牛人觉得"大牛"这层已经到顶了，但大多数"大牛"估计应该是有自知之明的，他们知道自己现在还没有爬到半山腰，也就勉强能算个半桶水的水平，其中有些爬到这层没有累趴下，仍然能量充沛，并且又有志者，还是会继续往更上一层楼爬的。</p>
<p>看到这里，也许有些菜鸟、大虾、牛人想不明白了，还有比"大牛"们更高的楼层，那会是什么样的楼层？下面就来看看第5层楼的奥妙。</p>
<p><strong>第5层 专家</strong></p>
<p>当大牛们真正动手做一个操作系统或者类似的其他软件时，他们就会发现自己的基本功仍然有很多的不足。以内存管理为例，如果直接抄袭Linux或者其他开源操作系统的内存管理算法，会被人看不起的，如果自动动手实现一个内存管理算法，他会发现现在有关内存管理方法的算法数量众多，自己并没有全部学过和实践过，不知道到底该用那种内存管理算法。</p>
<p>看到这里，可能有些人已经明白第5层楼的奥妙了，那就是需要做基础研究，当然在计算机里，最重要的就是"计算"二字，程序员要做基础研究，主要的内容就是研究非数值"计算"。</p>
<p>非数值计算可是一个非常庞大的领域，不仅时下热门的"多核计算"与"云计算"属于非数值计算范畴，就是软件需求、设计、测试、调试、评估、质量控制、软件工程等本质上也属于非数值计算的范畴，甚至芯片硬件设计也同样牵涉到非数值计算。如果你还没有真正领悟"计算"二字的含义，那么你就没有机会进到这层楼来。</p>
<p>可能有人仍然没有明白为什么比尔&#183;盖茨被划在了大牛层，没有进到这层来。虽然比尔&#183;盖茨大学未毕业，学历不够，但是家有藏书2万余册，进入软件这个行业比绝大部分人都早，撇开他的商业才能不谈，即使只看他的技术水平，也可以算得上是学富五车，顶上几个普通的计算机软件博士之和是没有问题的，比起 Linus Torvalds之类的"大牛"们应该技高一筹才对，怎么还进不了这层楼呢？</p>
<p>非常遗憾的是，从Windows操作系统的实现来看，其对计算的理解是很肤浅的，如果把Google对计算方面的理解比做大学生，比尔&#183;盖茨只能算做一个初中生，所以比尔&#183;盖茨永远只能做个大牛人，成不了"专家"。</p>
<p>看到这里，也许国内的大牛们要高兴起来了，原来比尔&#183;盖茨也只和我等在同一个层次，只要再升一层就可以超越比尔&#183;盖茨了。不过爬到这层可没有从"牛人"升为"大牛"那么简单，人家比尔&#183;盖茨都家有2万多册书，让你看个500~1000本以上的专业书籍并掌握好它应该要求不高吧。当然，这并不是主要的条件，更重要的是，需要到专业的学术站点去学习了，到ACM，IEEE，Elsevier，SpringerLink，SIAM等地方去下载论文应该成为你的定期功课，使用Google搜索引擎中的学术搜索更是应该成为你的日常必修课。此外，你还得经常关注是否有与你研究相关的开源项目冒出来，例如当听到有TBB这样针对多核的开源项目时，你应该第一时间到Google里输入"TBB"搜索一下，将其源代码下载下来好好研究一番，这样也许你的一只脚已经快迈进了这层楼的门槛。</p>
<p>当你象我上面说的那样去做了以后，随着时间的推移，总会有某天，你发现，在很多小的领域里，你已经学不到什么新东西了，所有最新出来的研究成果你几乎都知道。此时你会发现你比在做"牛人"和"大牛"时的水平不知高出了多少，但是你一点也"牛"不起来，因为你学的知识和思想都是别人提出来的，你自己并没有多少自己的知识和思想分享给别人，所以你还得继续往楼上爬才行。</p>
<p>我不知道国内的"专家"到底有多少，不过有一点可以肯定的是，如果把那些专门蒙大家的"砖家"也算上的话，我们的砖家比西方的要多得多。</p>
<p><strong>第6层 学者</strong></p>
<p>当"专家"们想继续往上一层楼爬时，他们几乎一眼就可以看到楼梯的入口，不过令他们吃惊的是，楼梯入口处竖了一道高高的门槛，上面写着"创新"二字。不幸的是，大多数人在爬到第5层楼时已经体能消耗过度，无力翻过这道门槛。</p>
<p>有少数体能充足者，可以轻易翻越这道门槛，但是并不意味着体力消耗过度者就无法翻越，因为你只是暂时还没有掌握恢复体能的方法而已，当掌握了恢复体能的方法，将体能恢复后，你就可以轻易地翻越这道门槛了。</p>
<p>怎么才能将体能恢复呢？我们的老祖宗"孔子"早就教导过我们"温故而知新"，在英文里，研究的单词是"research"，其前缀"re" 和"search"分别是什么意思不用我解释吧。或许有些人觉得"温故而知新"和"research"有些抽象，不好理解，我再给打个简单的比方，比如你在爬一座高山，爬了半天，中途体力不支，怎么恢复体力呢？自然是休息一下，重新进食一些食物，体力很快就可以得到恢复。</p>
<p>由此可知，对体能消耗过度者，休息＋重新进食通常是恢复体能的最佳选择。可惜的是，国内的老板们并不懂得这点，他们的公司里不仅连正常国家规定的休息时间都不给足，有些公司甚至有员工"过劳死"出现。所以国内能翻越"创新"这道门槛的人是"少之又少"，和西方比起来估计是数量级的差别。</p>
<p>再说说重新进食的问题，这个重新进食是有讲究的，需要进食一些基础性易消化的简单食物，不能进食山珍海味级的复杂食物，否则很难快速吸收。以查找为例，并不是去天天盯着那些复杂的查找结构和算法进行研究，你需要做的是将二分查找、哈希查找、普通二叉树查找等基础性的知识好好地复习几遍。</p>
<p>以哈希查找为例，首先你需要去将各种冲突解决方法如链式结构、二次哈希等编写一遍，再试试不同种类的哈希函数，然后还需要试试在硬盘中如何实现哈希查找，并考虑数据从硬盘读到内存后，如何组织硬盘中的数据才能快速地在内存中构建出哈希表来，...，这样你可能需要将一个哈希表写上十几个不同的版本，并比较各个版本的性能、功能方面的区别和适用范围。</p>
<p>总之，对任何一种简单的东西，你需要考虑各种各样的需求，以需求来驱动研究。最后你将各种最基础性的查找结构和算法都了然于胸后，或许某天你再看其他更复杂的查找算法，或者你在散步时，脑袋里灵光一现，突然间就发现了更好的方法，也就从专家晋升为"学者"了。</p>
<p>学者所做的事情，通常都是在前人的基础上，进行一些小的优化和改进，例如别人发明了链式基数排序的方法，你第1个发现使用一定的方法，可以用数组替代链表进行基数排序，性能还能得到进一步提高。</p>
<p>由于学者需要的只是一些小的优化改进，因此中国还是有一定数量的学者。不过和国外的数量比起来，估计少了一个数量级而已。</p>
<p>也许有人会觉得现在中国许多公司申请专利的数量达到甚至超过西方发达国家了，我们的学者数量应该不会比他们少多少。因此，有必要把专利和这里说的创新的区别解释一下。</p>
<p>所谓专利者，只要是以前没有的，新的东西，都可以申请专利；甚至是以前有的东西，你把他用到了一个新的领域的产品里去，也可以申请专利。比如你在房子里造一个水泥柱子，只要以前没有人就这件事申请专利，那么你就可以申请专利，并且下次你把水泥柱子挪一个位置，又可以申请一个新的专利；或者你在一个柜子上打上几个孔，下次又把孔的位置改一改，...，均可申请专利。</p>
<p>这层楼里所说的创新，是指学术层面的创新，是基础研究方面的创新，和专利的概念是完全不同的，难度也是完全不同的。你即使申请了一万个象那种打孔一类的专利，加起来也够不到这层楼里的一个创新。</p>
<p>当你爬到第6层楼时，你也许会有一种突破极限的快感，因为你终于把那道高高的写着"创新"二字的门槛给翻过去了，实现了"0"的突破。这时，你也许有一种"独上高楼，欲望尽天涯路"的感觉，但是很快你会发现看到的都是比较近的路，远处的路根本看不清楚。如果你还有足够的体力的话，你会想爬到更高一层的楼层去。</p>
<p><strong>第7层 大师</strong></p>
<p>从第6层楼爬到第7层楼，并没有多少捷径可走，主要看你有没有足够的能量。你如果能象Hoare一样设计出一个快速排序的算法；或者象Eugene W. Myers一样设计出了一个用编辑图的最短路径模型来解决diff问题的算法；或者象M.J.D. Powell一样提出了一个能够处理非线性规划问题的SQP方法；或者你发现基于比较的排序算法，它的复杂度下界为O(NLogN)；或者你发现用栈可以将递归的算法变成非递归的；或者你设计出一个红黑树或者AVL树之类的查找结构；或者你设计出一个象C++或Java一样的语言；或者你发明了 UML；...，你就爬到了第7层，晋升为"大师"了。</p>
<p>上面举的这些例子中，其中有些人站的楼层比这层高，这里只是为了形象说明而举例他们的某个成就。从上面列出的一些大师的贡献可以看出，成为大师必须要有较大的贡献。首先解决问题必须是比较重要的，其次你要比前辈们在某方面有一个较大的提高，或者你解决的是一个全新的以前没有解决过的问题；最重要的是，主要的思路和方法必须是你自己提供的，不再是在别人的思路基础上进行的优化和改进。</p>
<p>看了上面这些要求，如果能量不够的话，你也许会觉得有些困难，所以不是每个人都能成为"大师"的。中国软件业里能称得上是"大师"的人，用屈指可数来形容，估计是绰绰有余。值得一提得是，国外的"大师"就象我们的"大牛"一样满天飞的多。</p>
<p>我把我猜测本国有可能进到这层楼的大师列一下，以起个抛砖引玉的作用。汉王的"手写识别"技术由于是完全保密的，不知道它里面用了什么思想，原创思想占的比重有多少，因此不知道该把它划到这层楼还是更高一层楼去。原山东大学王小云教授破解DES和MD5算法时，用到的方法不知道是不是完全原创的，如果是的话也可进到这层楼来。</p>
<p>陈景润虽然没有彻底解决哥德巴赫猜想，但他在解决问题时所用的方法是创新的，因此也可以进到这层楼来。当然，如果能彻底解决哥德巴赫猜想，那么可以算到更高的楼层去。</p>
<p>求伯君和王志东等大牛们，他们在做WPS和表格处理之类的软件时，不知是否有较大的原创算法在里面，如果有的话就算我错把他们划到了大牛层。由于所学有限，不知道国内还有那些人能够得上"大师"的级别，或许有少量做研究的教授、院士们，可以达到这个级别，有知道的不妨回个帖子晾一晾。</p>
<p>鉴于"大师"这个称号的光环效应，相信有不少人梦想着成为"大师"。或许你看了前面举的一些大师的例子，你会觉得要成为大师非常困难。不妨说一下，现在有一条通往"大师"之路的捷径打开了，那就是多核计算领域，有大量的处女地等待大家去挖掘。</p>
<p>以前在单核时代开发的各种算法，现在都需要改写成并行的。数据结构与算法、图像处理、数值计算、操作系统、编译器、测试调试等各个领域，都存在大量的机会，可以让你进到这层楼来，甚至有可能让你进到更高一层楼去。<br /><strong><br />第8层 科学家</strong></p>
<p>科学家向来都是一个神圣的称号，因此我把他放在了&#8220;大师&#8221;之上。要成为科学家，你的贡献必须超越大师，不妨随便举一些例子。</p>
<p>如果你象Dijkstra一样设计了ALGOL语言，提出了程序设计的三种基本结构：顺序、选择、循环，那么你可以爬到第8层楼来。顺便说一下，即使抛开这个成果，Dijkstra凭他的PV操作和信号量概念的提出，同样可以进到这层楼。</p>
<p>如果你象Don Knuth一样，是数据结构与算法这门学科的重要奠基者，你也可以进到这层楼来。当然，数据结构和算法这门学科不是某个人开创的，是许多大师和科学家集体开创的。</p>
<p>如果你象巴科斯一样发明了Fortran语言，并提出了巴科斯范式，对高级程序语言的发展起了重要作用，你也可以进到这层楼来。</p>
<p>或者你象Ken Thompson、Dennis Ritchie一样发明了Unix操作系统和功能强大、高效、灵活、表达力强的C语言，对操作系统理论和高级编程语言均作出重大贡献，那么你也可以进到这层楼来。</p>
<p>或者你有Frederick P. Brooks一样机会，可以去领导开发IBM的大型计算机System/360和OS/360操作系统，并在失败后反思总结，写出《人月神话》，对软件工程作出里程碑式的贡献，你也可以进到这层来。</p>
<p>或者你提出了面向对象设计的基本思想，或者你设计了互联网的TCP/IP协议，或者你象Steven A.Cook一样奠定NP完全性的理论基础，或者你象Frances Allen一样专注于并行计算来实现编译技术，在编译优化理论和技术取得基础性的成就，&#8230;，均可进入这层。</p>
<p>当然，如果你发明了C++语言或者Java语言，你进不到这层来，因为你用到的主要思想都是这层楼中的科学家提出的，你自己并没有没有多少原创思想在里面。</p>
<p>看了上面列出的科学家的成就，你会发现，要成为&#8220;科学家&#8221;，通常要开创一门分支学科，或者是这个分支学科的奠基者，或者在某个分支学科里作出里程碑式的重大贡献。如果做不到这些的话，那么你能象Andrew C. Yao（姚期智）一样在对计算理论的多个方向如伪随机数生成，密码学与通信复杂度等各个方向上作出重要贡献，成为集大成者，也可以进入这层楼。</p>
<p>成为&#8220;科学家&#8221;后，如果你有幸象Dijkstra一样，出现在一个非常重视科学的国度。当你去世时，你家乡满城的人都会自动地去为你送葬。不过如果不幸生错地方的话，能不挨&#8220;板砖&#8221;估计就算万幸了。</p>
<p>从上面随便举的一些例子中，你可能能猜到，西方科学家的数量是非常多的，于是你会想中国应该也有少量的科学家吧？我可以很负责任地告诉你一个不幸的结果，中国本土产生的科学家的数量为0。目前在国内，软件领域的唯一的科学家就是上面提过的姚期智，还是国外请回来的，并不是本土产生的。</p>
<p>可能你不同意我说的本土科学家数量为0的结论，因为你经常看到有许多公司里都有所谓&#8220;首席XX科学家&#8221;的头衔。我想说的是，这些所谓的&#8220;首席XX科学家&#8221;都是远远够不到这层楼的级别的，有些人的水平估计也就是一个&#8220;牛人&#8221;或&#8220;大牛&#8221;的级别，好一点的最多也就一个&#8220;学者&#8221;的级别。尤其是那些被称作&#8220;首席经X学家&#8221;的，基本上可以把称号改为&#8220;首席坑大家&#8221;。</p>
<p>虽然我国没有人能爬到这层楼上来，但是西方国家仍然有许多人爬到了比这层更高的楼上。如果要问我们比西方落后多少？那么可以简单地回答为：&#8220;落后了三层楼&#8221;。下面就来看看我们做梦都没有到过的更高一层楼的秘密。</p>
<p><strong>第9层 大科学家</strong></p>
<p>进入这层楼的门槛通常需要一些运气，比如某天有个苹果砸到你头上时，你碰巧发现了万有引力，那么你可以进到这层楼来。当然，万有引力几百年前就被人发现了，如果你现在到处嚷嚷着说你发现了万有引力，恐怕马上会有人打110，然后警察会把你送到不正常人类的聚集地去。因此，这里举万有引力的例子，只是说你要有类似的成就才能进到这层楼来。</p>
<p>牛顿发现万有引力定律开创了经典物理运动力学这门学科，如果你也能开创一门大的学科，那么你就从科学家晋升为&#8220;大科学家&#8221;。比如爱因斯坦创建了相对论，从一个小职员变成了大科学家。当然大科学家可远不止这两人，数学界里比物理学界更是多得多，如欧几里得创建了平面几何，笛卡尔开创解析几何，还有欧拉、高斯、莱布尼茨等数不清的人物，跟计算相关的大科学家则有图灵等人。</p>
<p>从上面列出的一些大科学家可以发现，他们的成就不仅是开创了一个大的学科，更重要的是他们的成就上升到了&#8220;公理&#8221;的层面。发现公理通常是需要一点运气的，如果你的运气不够好的话，另外还有一个笨办法也可以进到这层楼来，那就是成为集大成者。例如冯&#183;诺伊曼，对数学的所有分支都非常了解，许多领域都有较大的贡献，即使撇开他对计算机的开创贡献，成为大科学家照样绰绰有余。</p>
<p>当然，程序员们最关心的是自己有没有机会变成大科学家。既然计算机这门大学科的开创性成果早就被冯&#183;诺伊曼、图灵等人摘走了，那么程序员们是不是没有机会变成大科学家了呢？我们的古人说得好：&#8220;江山代有才人出，各领风骚数百年&#8221;，现在在计算机这门学科下面诞生了许多非常重要的大的分支，所以你还是有足够的机会进到这层楼的。</p>
<p>如果你能够彻底解决自然语言理解（机器翻译）这门学科中的核心问题，或者你在人工智能或者机器视觉（图像识别）方面有突破性的发现，那么你同样可以轻易地晋升为&#8220;大科学家&#8221;。这样当某天你老了去世时，或许那天国人已经觉醒，你也能享受到如Dijkstra一样的待遇，有满城甚至全国的人去为你送葬。</p>
<p>现在还剩下另外一个大家感兴趣的问题没有讨论，那就是这层中已经出现了牛顿、爱因斯坦、高斯等我们平常人都认为是顶级的科学家，是不是这层已经是楼顶了呢？相信还记得本文标题的人应该知道现在仅仅是第9层，还有第10层没有到达呢。可能不少人现在要感到困惑了，难道还有人站在比牛顿、爱因斯坦、高斯等人更高的楼层上？</p>
<p>这个世界上确实存在可以用一只手的手指数得清的那么几个人，他们爬到了第10层楼上。因此，第10层楼不是虚构的，而是确实存在的。如果对此有疑惑或者认为我在胡诌一番的话，那么不妨继续往下看下去，窥一下第10层楼的秘密。</p>
<p><strong>第10层 大哲</strong></p>
<p>看了这层楼的名字&#8220;大哲&#8221;，可能不少人已经猜到了这层楼的秘密，那就是你的成果必须要上升到哲学的高度，你才有机会能进到这层来。</p>
<p>当然，上升到哲学高度只是一个必要条件，牛顿的万有引力似乎也上升到了哲学的高度，因为不知道引力到底是怎么来的，但是牛顿没有被划到这一层，因为进到这层还有另外的条件，那就是你的成果必须引起了哲学上的深度思考，并能让人们的世界观向前跨进一大步。窃以为牛顿、爱因斯坦等人的成就还达不到让人们世界观向前跨进一大步的程度。</p>
<p>所以，这层楼中的人的成就对我们普通人认识世界非常重要，你可以不学相对论，但是你不可以不对这层楼的人所作出的成就不了解，否则你的世界观就是极其不完整的，会犯许多认识上的错误。不幸的是，中国的科普知识普及还不够到位，知道这层楼成就的人好像并不多，程序员中恐怕更少。下面就来看看这些用一只手的手指数得清的大哲们，到底有什么成就，能比万有引力定律和相对论还重要。</p>
<p>1、希尔伯特 (1862～1943)</p>
<p>第1位进到此楼层是一位名叫&#8220;希尔伯特&#8221;的大数学家，如果你学过《泛函分析》，那么你在学习希尔伯特空间时可能已经对这位大数学家有所了解；如果你不是学数学出身的，又对数学史不感兴趣的话，恐怕你从来没有听说过这个名字。不过如果我问一下，知不知道二次世界大战前世界数学中心在那里，你肯定会有兴趣想知道。</p>
<p>不妨说一下，二战前整个世界的数学中心就在德国的哥廷根，而我们这位大数学家希尔伯特便是它的统帅和灵魂人物。即使在二战期间，希特勒和丘吉尔也有协定，德国不轰炸牛津和剑桥，作为回报，英国不轰炸海德堡和哥廷根。</p>
<p>整个二十世纪上半期的超一流数学家，几乎都出自其门下。这里不妨举几个我们熟悉的人物，例如冯&#183;诺伊曼就曾受到他和他的学生施密特和外尔的思想影响，还到哥廷根大学任过希尔伯特的助手，钱学森的老师冯&#183;卡门是在哥廷根取得博士学位的。顺便提一下，这位大数学家发现当时物理学上出了很多大的成果如相对论和量子力学，但是这些物理学家的数学功力明显不足，因此有一段时间带领他的学生们研究过物理学，并独立发现了广义相对论，只是不好意思和物理学家争功劳，将广义相对论的功劳全部让给了爱因斯坦。</p>
<p>广义相对论相对于这位大数学家在数学上的贡献，其实是算不了什么的，只是由此可看出这位大数学家品格的高尚之处。如果再去看看牛顿之流的人物的品行，整天和莱布尼茨、虎克等人争功劳，利用自己的优势地位打压他人，甚至闹得上法庭，和这位希尔伯特先生比起来，简直就是个小丑。</p>
<p>说到这里，你可能对这位大数学家&#8220;希尔伯特&#8221;有了一些初步映象，感觉到了他的重要性，不过他在数学上的主要成就可不是几句话说得清楚的。首先，他是一位集大成者，精通当时数学所有分支领域，在数学的各个领域都有较大的贡献，当然这些成就只能让他成为一个大科学家，不能带他进入这层楼。事实上这位&#8220;希尔伯特&#8221;解决的任何一个数学问题都够不到这层楼的高度，那么他怎么混到这层楼来了呢？</p>
<p>话得从1900年说起，当时还很年轻的希尔伯特在当时的世界数学大会上做了一个报告，高屋建瓯地提出了著名的23个未解决的数学问题，然后整个二十世纪上半期，全世界的数学家们都在这23个问题的指导下展开研究，直到现在仍然有许多数学家受这23个问题的指导在进行研究。例如我们熟知的哥德巴赫猜想，就属于其中第8个问题素数分布的一个子问题。</p>
<p>如果用&#8220;高瞻远瞩&#8221;来形容这位大数学家的话，那么这个世界上恐怕没有第二个人再配得上&#8220;高瞻远瞩&#8221;这四个字，不论是欧拉、高斯、牛顿、爱因斯坦还是被誉为最有才华的数学家伽罗华，概不例外。</p>
<p>虽然那23个问题是归纳总结出来的，并不全是原创，但是其中有不少问题是可以上升到哲学的高度，引起深度思考的。可能大多数人都会觉得希尔伯特是进不到这层楼的，我们知道提出问题的人和解决问题的人是一样伟大的，何况他提出的问题是如此之多，基于这点，个人觉得应该让希尔伯特跨进这层楼的门槛里。</p>
<p>看完这位希尔伯特的成就，你可能会觉得对你的世界观并没有产生任何影响。确实如此，他提出的问题不是用来影响你的，而是用来影响其他大科学家和大哲的，下面再来说说另一位对他提出的23个问题中的第2个问题有杰出贡献的大哲，你就会感觉到大哲们的成果的威力了。</p>
<p>2、哥德尔 (1906~1978)</p>
<p>这位大哲的名字叫&#8220;哥德尔 (G&#246;del) &#8221;，你可能从来也没有听说过这个名字，即使你读了一个数学系的博士学位，如果你的研究方向不和这位大哲对口的话，你也不一定了解这位大哲的成就，更不知道他的成果对我们这个世界有何意义。</p>
<p>简单地说，这位大哲20多岁时就证明了两个定理，一个叫做&#8220;哥德尔完全性定理&#8221;，另一个更重要的叫做&#8220;哥德尔不完全性定理&#8221;。你也许会觉得奇怪，第 9层楼的成就就已经上升到了公理的高度，这种证明定理的事情不是学者和大师们做的事情吗？怎么能比第9层楼的成就还高呢？下面就来简单说一下这两个定理的含义，你就会明白这属于系统级的定理，绝不是普通的定理和公理所能比拟的。</p>
<p>&#8220;哥德尔完全性定理&#8221;证明了逻辑学的几条公理是完备的，即任何一个由这些公理所产生出的问题，在这个公理系统内可以判定它是真的还是假的，这个结论表明了我们人类所拥有的逻辑思维能力是完备的。这条定理并不能将其带入这层楼来，带其进入这层楼的是另一条定理。</p>
<p>&#8220;哥德尔不完全性定理&#8221;是在1930年证明的，它证明了现有数学的几条公理（ZF公理系统）是不完备的，即由这些公理产生出的问题，无法由这几条公理判断它是真的还是假的。例如希尔伯特23个问题中的第1个问题，也就是著名的康托尔连续统假设，哥德尔在1938年证明了现有公理系统中不能证明它是&#8220; 假&#8221;的，科恩（Cohen，或许也可以称得上是&#8220;半&#8221;个大哲）在1963年证明了现有公理系统不能证明它是&#8220;真&#8221;的。最有趣的是，即使你将某个不可判定的问题，作为一条新的公理加入进去，所组成的新的公理系统仍然是不完备的，即你无法构造一个有限条公理的系统，让这个公理系统是完备的。</p>
<p>也许你仍然无法理解上面这段话的含义，不妨先说一下它对我们现实世界的影响。你可能知道1936年出现的图灵机是现代计算机的理论模型，如果没有哥德尔不完全性定理的思想，图灵机什么时候能出来是很难说的，所以这位哥德尔可以算作计算机理论的奠基者的奠基者。计算机对我们这个世界产生的影响比原子弹大了多少，我想不用我说大家也都清楚。当然，对现实世界的影响只能把哥德尔同图灵等人一样划到大科学家那一层去，能进入这层乃是另有原因。</p>
<p>可能你看过《未来战士》、《黑客帝国》、《I，Robot》之类的科幻电影，于是你产生制造一个和人一样或者比人更高一级的智能机器人的想法，这就引入了一个达到哲学高度的问题，&#8220;人到底能不能制造出具有和人一样的思维能力的机器来？&#8221;。</p>
<p>我只能告诉你，&#8220;你的愿望是良好的，但现实是残酷的&#8221;。如果你仔细思考一下不完全性定理的含义，并结合现代计算机所具有的能力分析一下，你会发现这个问题的答案暂时是否定的。如果你想造出和人一样思维能力的机器，那么你需要去好好学习这位大哲及其后续研究者的成果，并在他们的基础上有新的突破才行。</p>
<p>为了说明这位大哲所研究领域的重要性，这里顺便再讨论一个我们日常争议不休的问题，那就是孔夫子的&#8220;人之初、性本善&#8221;以及西方认为&#8220;人之初、性本恶 &#8221;的观点孰优孰劣的问题。可能有许多人发现西方社会现在领先我们，于是就认为&#8220;性本恶&#8221;是对的，&#8220;性本善&#8221;是错的，中国应该抛弃以前的旧思想，改用西方的思想。当然也有一些老学究们，认为中国的人文思想是领先于西方的，自然而然地认为&#8220;性本善&#8221;是对的，&#8220;性本恶&#8221;是错的。</p>
<p>如果你学过大哲用过的公理化的分析方法，你就知道一套系统的多条公理间只要不会推导出矛盾的地方，即可以自圆其说，那么它可以看作是对的。这样你可以很轻易地给这个问题下一个结论，即&#8220;性本善&#8221;和&#8220;性本恶&#8221;是对等的，不存在孰优孰劣的问题，更不存在谁对谁错的问题。只要你不同时将&#8220;性本善&#8221;和&#8220;性本恶&#8221;放入一个系统内，那么是不会有问题的，甚至你也可以认为&#8220;人之初、既无善、亦无恶&#8221;，或者认为&#8220;人之初、部分善、部分恶&#8221;，都是可以自圆其说的，所以我们的老祖宗提出的思想并没有问题，之所以落后乃是其他原因造成的。这个问题其实在高斯所处的时代就有了结论，那时有人提出了非欧几何，即平行线公理问题，有人认为过一点可以作多条平行线，还有人认为平行线在无穷远点是相交的，和欧氏几何关于过一点只能作一条平行线的公理都是矛盾的，但是他们各自的系统内推导出的结论都是正确的。</p>
<p>上面说的只是对哥德尔不完全性定理的一些粗浅解析，实际上如果深入思考一下它的含义的话，你会发现它对物理学等许多学科有重大影响，包含的道理实在是深刻，远非一般的思想所能比拟，有兴趣者不妨&#8220;google&#8221;或&#8220;百度&#8221;一下&#8220;哥德尔&#8221;。或许只有我们的老祖宗&#8220;老子&#8221;提出的哲学思想，深度可以有得一比。</p>
<p>哥德尔不完全性定理也给那些认为科学是严谨的人当头一棒，原来连数学这样的纯理论学科都是不严谨的，其他学科就更不用说了。</p>
<p>至此，已经说完数学上的大哲，下面不妨再看看物理学上的大哲，物理学上好像只出过一位叫&#8220;海森堡&#8221;的大哲（注：由于本人对物理学不甚了解，不知道&#8220;霍金&#8221;够不够得上大哲的称号）。</p>
<p>3、海森堡 (1901~1976)</p>
<p>海森堡这个名字相信没有几个人不知道的，大部分人在学习物理时都学过他的&#8220;测不准关系&#8221;，也就是因为这个&#8220;测不准关系&#8221;，海森堡爬到了第十层楼。</p>
<p>如果你看过《时间简史》和《霍金讲演录－黑洞、婴儿宇宙及其他》，你也许已经了解测不准关系的威力，所以这里不想做过多的讨论，只谈一些和本土产生的哲学思想相关的东西。</p>
<p>首先看看争论了几千年，并且现在仍然有人在争论不休的&#8220;宿命论&#8221;问题。霍金认为，只要这个宇宙有一个初始状态，粒子的运动是按照一定物理定律进行的（比如相对论、量子力学属于这些物理定律的一部分），那么所有的粒子运动轨迹将是确定的，然后只要你承认唯物论，即精神是由物质决定的，那么宿命论就是&#8220; 对&#8221;的。当然由于测不准关系的存在，对人而言，又是无法准确预测的，因此也可以将其看作是&#8220;不对&#8221;的。简单的说，可以认为宿命论是&#8220;对&#8221;的是绝对的，宿命论是&#8220;不对&#8221;的是相对的。</p>
<p>可能上面这段话你现在仍然难以理解，或许你又觉得你的命运并不是上天注定的，而是可以通过自己的努力可以改变的。我要告诉你的是，你在想什么也是事先已注定的，包括你在预测本身也是事先注定的，因为大脑思考问题最终是基本粒子运动的结果，而这些粒子的运动必然要遵循物理定律进行，所以你会不会努力，想不想努力，包括你在想你该不该努力这件事本身也是事先注定的。顺便说一下，你现在正在看这篇文章，可能正在想这个宿命论问题值得怀疑，或者觉得写得不够好，准备砸个板砖上来；或者你在想这篇问题写得有点意思，准备看完后转给朋友看一看；又或者你看到这里，觉得很累了，准备休息一下；&#8230;；这些都是上天事先就注定的。从你自身的相对角度看，因为你事先不知道后来会发生什么，也可以认为不是事先注定的，可能这句话有些不好理解，不妨好好理解前面说过的公理化思想。</p>
<p>如果你没看过《霍金讲演录－黑洞、婴儿宇宙及其他》，你可能会觉得很惊讶，宿命论历来不都被认为是唯心论吗，怎么由唯物论推导出了宿命论呢？现实就是这样和你开了一个大的玩笑，不过这个玩笑也是事先注定的。如果你再仔细用公理化的方法思考一下唯物论和唯心论的矛盾性，就像前面分析性善论和性恶论一样，你会发现唯物论、唯心论不一定就是冲突的，矛盾的双方是可以统一的，只要你不要同时将唯物和唯心放进同一个系统中就行。</p>
<p>当然也有聪明者仍然会怀疑宿命论问题的正确性，因为这里有一个前提条件，即宇宙要有一个初始状态。宇宙有没有初始状态，我们并不知道啊，虽然有大爆炸学说，但那也只是假说而已，并没有得到确证，有些人就认为宇宙是一直都存在的。这样看来似乎你又有合理的理由在怀疑宿命论了，不过我仍然要告诉你，你现在在怀疑宿命论仍然是事先注定的，不相信的话就来看看下面的分析。</p>
<p>虽然宇宙的初始状态值得怀疑，但是这个宇宙至少已经存在了一段时间，这点我想是毋庸置疑的。我们可以在我们已知的宇宙存在的这段时间内，任意取一个时间点t0，那么在这个时间点t0上，所有的粒子都有一个运动状态。在时间点t0之后的时间里，由于粒子运动是按照物理定律进行的，因此粒子运动轨迹由时间点t0的状态决定。说白一点，如果取100年前的一个时间点作为t0，那么现在的所有粒子运动状态100年前就已经确定了，如果取10000年前一个时间点作为t0，那么最近10000年内所有粒子运动的轨迹在10000年前就确定了，当然，你可以取更早的时间，比如100亿年前的时间点。</p>
<p>总之，现在你会发现宇宙有没有初始状态并不会影响宿命论的正确性，所以这个世界的一切都是注定的。只不过由于粒子间相互影响过于复杂，我们无法知道这些粒子的运动轨迹而已。当然，如果将测不准关系用上的话，那么就是这个运动轨迹对人来说是无法准确预测的，所以不妨开个玩笑：&#8220;算命先生经常算得不准大概是测不准关系的缘故吧&#8221;。</p>
<p>如果你再深入思考一下测不准关系，你会发现这是一个测量系统的问题。由于宿命论的存在，这个世界本身实际上是确定的，是&#8220;准&#8220;的，之所以测不准乃是我们人类所具有的测量能力依赖于基本粒子造成的。所以我在前面说宿命论是&#8220;不对&#8221;的是相对的，它是相对于我们人类的测量能力而言的。根岑（Gentzen，曾任希尔伯特的助手）在一个更强的系统内证明了ZF系统内的问题都是可判定的，从一个侧面说明这个世界本身是确定的。（注：它和哥德尔不完全性定理并不矛盾，由于数学上的复杂性，这里就不详细解释了）</p>
<p>不妨再想想我们老祖宗提出的&#8220;是庄周梦见了蝴蝶？还是蝴蝶梦见了庄周？&#8221;，&#8220;风动？幡动？还是心动？&#8221;之类的问题，当然以前你都认为这是纯粹的唯心主义，甚至认为是封建糟粕，但是如果结合测不准关系的内涵，再结合前面所说的公理化分析方法进行分析，估计你现在不敢轻易地下结论。</p>
<p>也许到现在你仍然无法理解为什么把大哲们划在了大科学家的上一层，你可能仍然觉得万有引力、相对论等成果是最伟大的。下面就来谈谈为什么大哲比大科学家高一层。</p>
<p>如果把人类在现有能力情况下，将来所能够拥有的知识总集看成是一个集合A，人类现在已有的知识总集看成是集合B，显然，集合B只是集合A的一个子集，并且是很小的一个子集。牛顿力学、相对论这些理论只能算作集合B里的一个子集，相对于集合A，只能算作是沧海一粟。换句话说，在人类现有能力可做的事情集合中，牛顿力学和相对论等理论给出了详细的办法让你可以做其中的一些事情，当然剩下的更多的事情是牛顿力学和相对论所无法解决的。</p>
<p>哥德尔不完全性定理和测不准关系的意义在于，它指出集合A的范围，即将人类现有能力发挥到极限的情况下，那些事情是你能做到的，那些是你不能做到的。当然，它并没有给出具体的方法让你去做你能做到的事情，它只是告诉我们我们人类现在发现的能力所能达到的极限。或许将来发现人类有其他新的未发现的能力，那么这个极限就被打破了。比如将来能发现不依赖于基本粒子的其他测量方法，并且测量过程中不会改变其他粒子的状态，那么测不准关系就被打破了。</p>
<p>看到这里，估计你已经发现了一些秘密，科学兜了一大圈，最终还是回到了哲学，也就是我们所认为的玄学上。同时你也会发现，我们老祖宗提出的所谓玄学，原来和现代科学是相通的，并非象某些人想像的那样全是糟粕。如果有人认为西方现代暂时领先我们，进而就认为西方古代就已经超越我们，我们老祖宗就已经落后西方，他们的思想都是糟粕的话，那么我认为他可能犯了崇洋媚外的毛病。我不得不化用一句周杰伦在春晚上的歌词送给他：&#8220;你不妨抓一副我们祖传的中医良方，治一治你那崇洋媚外的内伤&#8221;。顺便告诉他一下，中医用的阴阳五行理论，它的前提假设就是宿命论。</p>
<p>上面说的这几位大哲的成果，可能对你的世界观会有很大的影响，于是你可能会羡慕起这些大哲们的成果来。如果你有大志的话，你会希望有朝一日你也能变成大哲，但是你发现上面的大哲是研究数学和物理学的，而你是学计算机的程序员，那么是不是没有机会变成大哲呢？</p>
<p>如果你能将NP难题给彻底解决掉，意味着计算机内的计算的奥秘基本被揭开，或许你可以进到这层楼来；或者你能发现另外一套计算机可以理解的数学公理系统，并且这个公理系统是完备的，那么计算机取代人类进行思维的一个必要条件就满足了，计算机将具有真正意义上的&#8220;逻辑思维和推理能力&#8221;，你可以轻松地进到这层楼来。如果你发现了新的方法可以打破测不准关系，同样你也可以轻松地进到这层楼来。</p>
<p>如果你能彻底揭开人类抽象思维的奥妙，并让计算机懂得了如何创建抽象，具备抽象思维能力，那么也就具备了&#8220;设计能力&#8221;，可以取代人类进行各种设计了，你也可以轻松地进到这层楼来。顺便说一下，如果你对软件设计有真正深刻理解的话，就会明白这不是在写科幻小说。对此感兴趣者，不妨好好地研究一下程序切片方面的技术，会让你对软件设计和测试等方面的理解有质的提高，或许有一天你能打开这扇大门。</p>
<p>当然，计算机要完全取代人还有其他必要条件，后面还会提及。</p>
<p>值得一提的是，虽然第10层楼是本文中所写的最高层，但是大哲们并没有觉得他们到了顶层，他们通常都还会努力寻找通往更高一层的楼梯。如果你也有成为天下第一的想法，那么你或许会想要做什么事情才能超越大哲们的成就，当然，这都得依赖于找到更高一层楼的楼梯。</p>
<p>个人认为，再往上一层楼的楼梯是通往天堂的道路，也就是说第11层楼的名字叫&#8220;天堂&#8221;，是&#8220;上帝&#8221;住的地方，而不是人住的地方。如果将来某天有人能爬到天堂的话，那么他已经不是人了，而是由人变成了&#8220;上帝&#8221;。</p>
<p>你也许会怀疑这个世界到底有没有&#8220;天堂&#8221;，&#8220;上帝&#8221;是否根本就不存在，我也很有同感。因此有必要再写上一段文字，讨论一下&#8220;上帝&#8221;的问题。如果你想了解天堂的奥妙，有没有办法让你变成&#8220;上帝&#8221;，不妨看看继续往下看看第11层楼的玄妙。注意我这里用的是&#8220;玄妙&#8221;二字，因为上帝在大部分人眼里估计都是&#8220; 玄之又玄&#8221;的东西。</p>
<p><strong>第11层 上帝</strong></p>
<p>看了上面的小标题，你可能会觉得奇怪，这篇文章不是讲&#8220;程序员的十层楼&#8221;吗？怎么冒出了第11层来了？</p>
<p>其实这并不矛盾，程序员确实只有十层楼，因为爬到第11层时，已经变成上帝，不再是程序员了；所以超出10层楼本身并不重要，关键的问题是看你有没有能力变成上帝。</p>
<p>1、谁是上帝？</p>
<p>菜鸟们认为Linus Torvalds是程序员中的上帝，看完了前面各层楼的介绍，此时再看到这句话，相信你要忍不住在心里笑起来。当然，你会不会笑起来是事先注定的。Don Knuth也不是上帝，他离上帝还有三层楼的距离。即使是大哲们，他们离天堂也还差一层楼，因此这个世界上有史以来还没有任何一个人变成过上帝。</p>
<p>我们感兴趣的是，将来会不会有人爬到比大哲们更高的楼层上，变成了上帝。</p>
<p>要变成上帝，你得有上帝一样的能力，上帝会造人，你会吗？</p>
<p>你也许会怯生生地问：&#8220;我可以和爱人生小孩，算不算造人？&#8221;，你可能还会理直气壮地说：&#8220;现在生物学上都可以克隆人了，早就有人掌握了造人的方法&#8221;。</p>
<p>事实上克隆人需要有人的体细胞，必须要先有人才会有体细胞。上帝造人时，这个世界上并没有人，是从无生命的物质&#8220;尘土&#8221;中创造出的人。因此，用最原始的方法生人和克隆人都是从有生命信息的物质中生人，不能算作造人。</p>
<p>这样看来，你根本不会造人，不过我可以告诉你一个&#8220;玄方&#8221;，让你有机会学会如何造人。</p>
<p>如果你揭开了人类情感的奥秘，让计算机也可以拥有和人类一样的情感，那么计算机将可以理解人类的需求，具有了&#8220;情商&#8221;，将具有完整的和人一样的能力。此时，人类进化到了机器人，科幻小说将变成现实，也就是说你已经掌握了真正的造人能力，晋升为&#8220;上帝&#8221;了。</p>
<p>未来到底有没有人能变成&#8220;上帝&#8221;，人能不能进化到机器人，这是宿命论中事先注定了的。说到这里，不妨再告诉你一个打破宿命论的方法，这个方法就是你要爬到比上帝还要高的楼层。</p>
<p>&#8220;还有比上帝还高的楼层？&#8221;，你可能会第1时间内冒出这个问题，其实我也有同样的怀疑。因此在写第12层楼前，有必要弄清楚它到底存不存在，即你可不可以骑到上帝的头上的问题。</p>
<p>2. 骑到上帝的头上？</p>
<p>为了解决是否可以骑到上帝的头上这个问题，不妨先假设存在比上帝高的楼层，也就是存在打破宿命论的方法。</p>
<p>宿命论的本质原因是因为时间是单向运行，不可逆转造成的。如果你找到一种可以使时间逆转的方法，那么你就打破了宿命论，爬到了比上帝还高的楼层。</p>
<p>看到这里，你也许会摆脱刚才陷于宿命论的困惑情绪，变得充满希望般高兴起来。不过，如果你的逻辑思维能力足够好，仔细思考一下，会发现存在一个逻辑上的悖论。</p>
<p>在你找到时间逆转的方法之前，显然这个世界仍然是需要服从宿命论的，也就是说你能不能找到打破宿命论的方法是事先注定的。假设你在某个时间点t0处找到了打破宿命论的方法，你在打破宿命论后，想利用时间逆转的方法回到某个时间点t2。下面来看看你到底能不能回到时间点t2。</p>
<p>取位于t0和t2之间的任意一个时间点t1，你在回到时间点t2之前，必须先经过时间点t1，考虑你到达t1的那一时刻，由于t1比t0要早，这个时间点上你还没有找到时间逆转的方法，所以到了时间t1点后，你无法再使用时间逆转的能力回到时间点t2去，所以你永远也回不到时间点t2，由于时间点 t2是任意取的，因此，你永远也无法使时间逆转，或者说你根本就没打破过宿命论，这与你在时间点t0打破了宿命论产生了矛盾。</p>
<p>上面这段话看起来似乎有点像&#8220;人永远迈不出一步&#8221;的诡辩一样，你可能会想返回到时间点t1时，仍然可以拥有时间逆转能力啊。不过你又会发现一个新的问题，时间点t1本来是没有时间逆转能力的，现在又认为时间点t1又有时间逆转能力，那时间点t1到底是有还是没有时间逆转能力呢？或者说在时间点t0 前，宿命论注定了时间点t1是没有时间逆转能力的，现在你又认为时间点t1具有时间逆转能力，那么这两个时间点t1究竟是不是同一个时间点？如果不是同一个时间点，说明你没有回到过去；如果是同一个时间点的话，岂不是自相矛盾吗？</p>
<p>为了说得更形象一些，不妨假设你坐一艘超光速飞船，准备从时间点t0回到时间点t2去，假设你回到t2后，随着时间的流逝，又达到了时间点t0，如果这时你又再次坐超光速飞船返回时间点t2，那么一个值得思考的问题就出现了，&#8220;你在时间点t2能不能看到上次返回时间点t2的飞船？&#8221;</p>
<p>如果回答不能看到飞船，那么上次返回的飞船那里去了呢？显然很难解释通。如果回答能看到飞船，那么你可以到达时间点t2后，下次时间到达t0时，你又坐飞船返回t2，这次你将可以看到上两次的两艘飞船。如果这样一直循环下去，最后你会发现你可以在时间点t2看到无穷多的飞船。用程序员的术语说，叫做 &#8220;程序陷入了死循环&#8221;，最后系统必然会出现&#8220;Out of Memory&#8221;现象而崩溃。</p>
<p>当然，你也可以认为有其他的方法，不需要飞船，可以一次性从时间点t0直接跳跃到时间点t2，并不需要经过时间点t1。下面不妨来分析一下这个方法是否可行。</p>
<p>既然是直接跳跃到时间点t2，那么你必然是在一个无穷小的时间里出现在时间点t2的某个空间里，例如你要在时间点t2回到某个广场上。首先说明一下为什么是无穷小的时间里出现的，因为如果不是无穷小的时间里出现的话，那么必然可以取到一个时间点t1，会导致前面所说的时间点t1上出现悖论。</p>
<p>你在广场上出现的时，广场上的空气必然要为你让开空间，而这是在无穷小的时间里完成的，那么很容易推导出你周围的空气获得的加速度和速度都是无穷大，因而它具有的动能也是无穷大，无穷大的能量和无穷大的速度意味着什么？一只鸟都可以将飞机撞下来，如果宇宙是有限大的话，它可以让这个宇宙炸毁无穷次；即使宇宙是无限大，它也足以让宇宙炸毁一次。宇宙都毁灭了，又何来的时间？还能说你回到了时间点t2吗？</p>
<p>也许上面说的这些你仍然难以相信，不妨再说得更现实一些，假设你要回到100年前的一个时间点，这100年中，天上有多少流星湮灭了？有多少新星生成了？宇宙膨胀了多少？你有能力让湮灭的流星复原、生成的新星重新返回未生成前的状态，膨胀的宇宙收缩回去吗？如果这些东西的状态没有回复到100年前，又怎么能说明你回到的是100年前的时间点呢?</p>
<p>根据上面的推导和分析，个人认为使时间逆转的方法是不存在的，所以第12层楼是不存在的，自然没有人可以骑到&#8220;上帝&#8221;的头上。</p>
<p>宿命论将在有时间的时间里永远统治这个世界。</p><img src ="http://www.cppblog.com/lshain/aggbug/149272.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lshain/" target="_blank">Lshain</a> 2011-06-23 14:44 <a href="http://www.cppblog.com/lshain/articles/149272.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>