﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Tinysun-随笔分类-C/C++</title><link>http://www.blogjava.net/tinysun/category/37792.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 19 Jan 2011 05:55:57 GMT</lastBuildDate><pubDate>Wed, 19 Jan 2011 05:55:57 GMT</pubDate><ttl>60</ttl><item><title>理解可执行程序的各种神器 </title><link>http://www.blogjava.net/tinysun/archive/2011/01/19/343184.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Tue, 18 Jan 2011 16:05:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2011/01/19/343184.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/343184.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2011/01/19/343184.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/343184.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/343184.html</trackback:ping><description><![CDATA[<div id="detail" style="line-height: 1.3">
<p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">ldd</span></strong><span style="color: black; font-family: 宋体">查看应用程序链接了哪些动态库。 </span></p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">nm</span></strong><span style="color: black; font-family: 宋体">列出目标文件中包含的符号信息。</span></p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">size</span></strong><span style="color: black; font-family: 宋体">列出各个段的大小及总的大小。</span></p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">strings</span></strong><span style="color: black; font-family: 宋体">列出文件中的字符串。</span></p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">readelf</span></strong><span style="color: black; font-family: 宋体">读取elf文件的完整结构。</span></p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">objdump</span></strong><span style="color: black; font-family: 宋体">导出目标文件的相关信息（elf文件相关工具的源头）。</span></p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">gdb</span></strong><span style="color: black; font-family: 宋体">对文件的执行过程进行调试分析，设置断点(b)、单步执行(n)、函数调用追踪(bt)、反汇编(disassemble)。</span></p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">strace</span></strong><span style="color: black; font-family: 宋体">跟踪程序中的系统调用及信号处理信息。</span></p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">LD_DEBUG</span></strong><span style="color: black; font-family: 宋体">通过设置这个环境变量，可以方便的看到 loader 的加载过程（包括库的加载，符号解析等过程），使用【LD_DEBUG=help 可执行文件路径】可查看使用帮助。</span></p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">LD_PRELOAD</span></strong><span style="color: black; font-family: 宋体">环境变量指定的共享库会被预先加载，如果出现重名的函数，预先加载的函数将会被调用，如在预先加载的库中包含自定义的puts函数，则在执行程序时将使用自定义版本的puts函数，而不是libc库中的puts函数。</span></p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">proc</span></strong><strong><span style="color: black; font-family: 宋体">文件系统</span></strong><span style="color: black; font-family: 宋体">中包含进程的地址空间映射关系，具体查看/proc/进程id/maps文件的内容。</span></p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">valgrind</span></strong><span style="color: black; font-family: 宋体">工具对可执行程序文件进行内存检查（还有cache模拟、调用过程跟踪等功能），以避免内存泄露等问题。</span></p>
<p style="margin: 0cm 0cm 0pt"><strong><span style="color: black; font-family: 宋体">addrline</span></strong><span style="color: black; font-family: 宋体">将可执行文件中的地址转换为其在源文件中对应的位置（文件名：行号）。</span></p>
</div>
<img src ="http://www.blogjava.net/tinysun/aggbug/343184.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2011-01-19 00:05 <a href="http://www.blogjava.net/tinysun/archive/2011/01/19/343184.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>。。。。</title><link>http://www.blogjava.net/tinysun/archive/2010/10/11/334455.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Mon, 11 Oct 2010 09:20:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/10/11/334455.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/334455.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/10/11/334455.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/334455.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/334455.html</trackback:ping><description><![CDATA[http://blog.csdn.net/absurd/archive/2006/07/25/976820.aspx
<div>
<meta http-equiv="content-type" content="text/html; charset=utf-8" /><a href="http://blog.csdn.net/eroswang/category/322381.aspx?PageNumber=2">http://blog.csdn.net/eroswang/category/322381.aspx?PageNumber=2</a></div>
<img src ="http://www.blogjava.net/tinysun/aggbug/334455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-10-11 17:20 <a href="http://www.blogjava.net/tinysun/archive/2010/10/11/334455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>STL算法学习</title><link>http://www.blogjava.net/tinysun/archive/2010/08/27/330074.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Fri, 27 Aug 2010 08:11:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/08/27/330074.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/330074.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/08/27/330074.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/330074.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/330074.html</trackback:ping><description><![CDATA[<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">STL算法学习，小结如下：</font></font></font></font></font></p>
<p>
<font size="3"><font size="3"><font><font size="3"><font><font size="3"><font><font size="3"><font>				<font style="background-color: #ff0099;">前提:
</font></font></font></font></font></font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">下载stl源码： &nbsp;<a href="http://www.sgi.com/tech/stl/download.html">http://www.sgi.com/tech/stl/download.html</a><br />
打开网页：&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.sgi.com/tech/stl/stl_index.html">http://www.sgi.com/tech/stl/stl_index.html</a></font></font></font></font></font></p>
<p>
<font size="3"><font size="3"><font><font size="3"><font><font size="3"><font><font size="3"><font>				<font style="background-color: #ff0099;">一&nbsp;&nbsp; 函数对象： 因为很多的算法中多使用了函数对象
</font></font></font></font></font></font></font></font></font></font></p>
<p>
<font size="3"><font size="3"><font size="3"><font size="3"><font size="3">				<br />
二元函数对象，V1和V2为输入，V3为结果</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">plus&lt;T&gt;:<br />
&nbsp; transform(V1.begin(), V1.end(), V2.begin(), V3.begin(),plus&lt;double&gt;());</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">其他的二元函数对象：minus,multiples,divieds,modulus.</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">二元断言函数对象，使用时需要bind2nd（）或bind1st（）来绑定比较对象。</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">less&lt;T&gt;:<br />
&nbsp; find_if(L.begin(), L.end(), bind2nd(less&lt;int&gt;(), 0));</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">其他的二元断言函数：equal_to,notequal_to,greater,greater_equal,less_equal,logical_and,logical_or</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">二元逻辑函数</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">binary_negate:<br />
const char* wptr = find_if(str, str + MAXLEN,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; compose2(not2(logical_or&lt;bool&gt;()),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bind2nd(equal_to&lt;char&gt;(), ' '),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bind2nd(equal_to&lt;char&gt;(), '"n')));</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">一元函数对象</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">negate：<br />
transform(V1.begin(), V1.end(), V2.begin(),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; negate&lt;int&gt;());</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">一元断定函数对象</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">logical_not:<br />
&nbsp; transform(V.begin(), V.end(), V.begin(), logical_not&lt;bool&gt;());</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">一元逻辑函数</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">unary_negate:</font></font></font></font></font></p>
<p>
<font size="3"><font><font size="3"><font><font size="3"><font><font size="3"><font><font size="3"><font>				<br />
<font style="background-color: #ff0099;">二&nbsp;&nbsp; 函数对象发生器：主要用来填充序列。<br />
<br />
<br />
</font>产生不重复的随机数：<br />
// Generate unique random numbers from 0 to mod:<br />
class URandGen {<br />
&nbsp; std::set&lt;int&gt; used;<br />
&nbsp; int limit;<br />
public:<br />
&nbsp; URandGen(int lim) : limit(lim) {<br />
&nbsp;&nbsp;&nbsp; srand(time(0));<br />
&nbsp; }<br />
&nbsp; int operator()() {<br />
&nbsp;&nbsp;&nbsp; while(true) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i = int(rand()) % limit;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(used.find(i) == used.end()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; used.insert(i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
};</font></font></font></font></font></font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">const int sz = 10;<br />
const int max = 50;<br />
vector&lt;int&gt; x(sz), y(sz), r(sz);<br />
//An integer random number generator:<br />
URandGen urg(max);<br />
generate_n(x.begin(), sz, urg);</font></font></font></font></font></p>
<p>
<font size="3"><font size="3"><font><font size="3"><font><font size="3"><font><font size="3"><font>				<font style="background-color: #ff0099;">三 函数对象适配器 ： 将函数转化为函数对象
</font></font></font></font></font></font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">ptr_fun:一般函数适配器</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">一元实例：<br />
transform(first, last, first,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; compose1(negate&lt;double&gt;, ptr_fun(fabs)));</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">二元实例：<br />
list&lt;char*&gt;::iterator item = <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; find_if(L.begin(), L.end(),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; not1(binder2nd(ptr_fun(strcmp), "OK")));</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">not1：对一元的断定函数对象取反的适配器。</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">not2: 对二元的断定函数对象取反的适配器。</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">mem_fun与mem_fun_ref：类成员函数的适配器,区别是一个需要指针，而另一个仅需要一般对象。如下：<br />
shape是一个指针变量，则foreach(v.begin(),v.end(),mem_fun(&amp;shape::draw));<br />
但如果shape是一般的变量，不是指针，则foreach（v.begin(),v.end(),mem_fun_ref(&amp;shape::draw)）；</font></font></font></font></font></p>
<p>
<font size="3"><font size="3"><font><font size="3"><font><font size="3"><font><font size="3"><font>				<font style="background-color: #ff0099;">四&nbsp;&nbsp; 算法：
</font></font></font></font></font></font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">拷贝：<br />
copy（）<br />
reverse_copy()<br />
rotate_copy()<br />
remove_copy()&nbsp; 拷贝不等于某值的元素到另一个序列。<br />
remove_copy_if() 拷贝符合条件的到另一个序列。</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">填充和生成：<br />
fill()<br />
fill_n() 填充序列中的n个元素。<br />
generate（）为序列中的每个元素调用gen（）函数。</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">排列：<br />
next_permuttion() 后一个排列。<br />
prev_permutation()</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">partition() 划分，将满足条件的元素移动到序列的前面。<br />
stable_partition()</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">查找和替换：<br />
find（）<br />
binary_search() 在一个已经有顺序的序列上查找。<br />
find_if()<br />
search() 检查第二个序列是否在第一个序列中出现，且顺序相同。</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">删除：注意必须调用erase（）来真正删除<br />
remove（）<br />
unique（）删除相邻重复元素，最好现排序。</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">合并序列：<br />
merge（）</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">数值算法：<br />
accumulate（） 对序列的每个元素进行运算后求和。<br />
transform（） 也可以对每个元素进行运算。<br />
计数：<br />
size（）总个数。<br />
count（）等于某值的元素个数。</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">adjacent_difference 序列中的后一个减前与他相邻的前一个得到新的序列。</font></font></font></font></font></p>
<p><font size="3"><font size="3"><font size="3"><font size="3"><font size="3">adiacent_find </font></font></font></font></font></p>
<p>
<font size="3"><font size="3"><font><font size="3"><font><font size="3"><font><font size="3"><font>				<font style="background-color: #ff0099;">五&nbsp;&nbsp; 所有的算法：
</font></font></font></font></font></font></font></font></font></font></p>
<p>
<font size="3"><font><font size="3"><font><font size="3"><font><font size="3"><font><font size="3"><font>				<span>
<span>
<span style="font: 7pt 'Times New Roman';">&nbsp;&nbsp;&nbsp;&nbsp; </span>
</span>
</span>
<font size="2">
<strong>
<span>
<font face="Tahoma">accumlate</font>
</span>
</strong>
<span style="font-family: 宋体;">：</span>
<span>
<font face="Tahoma">iterator</font>
</span>
<span style="font-family: 宋体;">对标志的序列中的元素之和，加到一个由</span>
<span>
<font face="Tahoma">init</font>
</span>
<span style="font-family: 宋体;">指定的初始值上。重载的版本不再做加法，而是传进来的二元操作符被应用到元素上。</span>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">adjacent_different</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：创建一个新序列，该序列的每个新值都代表了当前元素与上一个元素的差。重载版本用指定的二元操作计算相邻元素的差。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">adjacent_find</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：在</span>
iterator
<span style="font-family: 宋体;">对标志的元素范围内，查找一对相邻的重复元素，如果找到返回一个</span>
ForwardIterator
<span style="font-family: 宋体;">，指向这对元素的第一个元素。否则返回</span>
last
<span style="font-family: 宋体;">。重载版本使用输入的二元操作符代替相等的判断。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">binary_search</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：在有序序列中查找</span>
value
<span style="font-family: 宋体;">，如果找到返回</span>
true
<span style="font-family: 宋体;">。重载的版本使用指定的比较函数对象或者函数指针来判断相等。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">copy</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：复制序列。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">copy_backward</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：除了元素以相反的顺序被拷贝外，别的和</span>
copy
<span style="font-family: 宋体;">相同。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">count</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：利用等于操作符，把标志范围类的元素与输入的值进行比较，并返回相等元素的个数。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">count_if</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：对于标志范围类的元素，应用输入的操作符，并返回结果为</span>
true
<span style="font-family: 宋体;">的次数。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">equal</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：如果两个序列在范围内的元素都相等，则</span>
equal
<span style="font-family: 宋体;">返回</span>
true
<span style="font-family: 宋体;">。重载版本使用输入的操作符代替了默认的等于操作符。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">equal_range</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：返回一对</span>
iterator
<span style="font-family: 宋体;">，第一个</span>
iterator
<span style="font-family: 宋体;">表示由</span>
lower_bound
<span style="font-family: 宋体;">返回的</span>
iterator
<span style="font-family: 宋体;">，第二个表示由</span>
upper_bound
<span style="font-family: 宋体;">返回的</span>
iterator
<span style="font-family: 宋体;">值。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">fill</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：将输入的值的拷贝赋给范围内的每个元素。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">fill_n</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：将输入的值赋值给</span>
first
<span style="font-family: 宋体;">到</span>
frist+n
<span style="font-family: 宋体;">范围内的元素。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">find</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：利用底层元素的等于操作符，对范围内的元素与输入的值进行比较。当匹配时，结束搜索，返回该元素的一个</span>
InputIterator
<span style="font-family: 宋体;">。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">find_if</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：使用输入的函数替代了等于操作符执行了</span>
find
<span style="font-family: 宋体;">。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">find_end</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：在范围内查找&#8220;由输入的另外一个</span>
iterator
<span style="font-family: 宋体;">对标志的第二个序列&#8221;的最后一次出现。重载版本中使用了用户输入的操作符替代等于操作。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">find_first_of</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：在范围内查找&#8220;由输入的另外一个</span>
iterator
<span style="font-family: 宋体;">对标志的第二个序列&#8221;中的任意一个元素的第一次出现。重载版本中使用了用户自定义的操作符。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">for_each</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：依次对范围内的所有元素执行输入的函数。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">generate</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：通过对输入的函数</span>
gen
<span style="font-family: 宋体;">的连续调用来填充指定的范围。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">generate_n</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：填充</span>
n
<span style="font-family: 宋体;">个元素。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">includes</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：判断</span>
[first1, last1)
<span style="font-family: 宋体;">的一个元素是否被包含在另外一个序列中。使用底层元素的</span>
&lt;=
<span style="font-family: 宋体;">操作符，重载版本使用用户输入的函数。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">inner_product</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：对两个序列做内积</span>
(
<span style="font-family: 宋体;">对应的元素相乘，再求和</span>
)
<span style="font-family: 宋体;">，并将内积加到一个输入的的初始值上。重载版本使用了用户定义的操作。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">inner_merge</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：合并两个排过序的连续序列，结果序列覆盖了两端范围，重载版本使用输入的操作进行排序。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">iter_swap</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：交换两个</span>
ForwardIterator
<span style="font-family: 宋体;">的值。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">lexicographical_compare</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：比较两个序列。重载版本使用了用户自定义的比较操作。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">lower_bound</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：返回一个</span>
iterator
<span style="font-family: 宋体;">，它指向在范围内的有序序列中可以插入指定值而不破坏容器顺序的第一个位置。重载函数使用了自定义的比较操作。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">max</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：返回两个元素中的较大的一个，重载版本使用了自定义的比较操作。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">max_element</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：返回一个</span>
iterator
<span style="font-family: 宋体;">，指出序列中最大的元素。重载版本使用自定义的比较操作。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">min</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：两个元素中的较小者。重载版本使用自定义的比较操作。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">min_element</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：类似与</span>
max_element
<span style="font-family: 宋体;">，不过返回最小的元素。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">merge</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：合并两个有序序列，并存放到另外一个序列中。重载版本使用自定义的比较。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">mismatch</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：并行的比较两个序列，指出第一个不匹配的位置，它返回一对</span>
iterator
<span style="font-family: 宋体;">，标志第一个不匹配的元素位置。如果都匹配，返回每个容器的</span>
last
<span style="font-family: 宋体;">。重载版本使用自定义的比较操作。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">next_permutation</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：取出当前范围内的排列，并将其重新排序为下一个排列。重载版本使用自定义的比较操作。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">nth_element</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：将范围内的序列重新排序，使所有小于第</span>
n
<span style="font-family: 宋体;">个元素的元素都出现在它前面，而大于它的都出现在后面，重载版本使用了自定义的比较操作。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">partial_sort</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：对整个序列做部分排序，被排序元素的个数正好可以被放到范围内。重载版本使用自定义的比较操作。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">partial_sort_copy</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：与</span>
partial_sort
<span style="font-family: 宋体;">相同，除了将经过排序的序列复制到另外一个容器。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">partial_sum</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：创建一个新的元素序列，其中每个元素的值代表了范围内该位置之前所有元素之和。重载版本使用了自定义操作替代加法。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">partition</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：对范围内元素重新排序，使用输入的函数，把计算结果为</span>
true
<span style="font-family: 宋体;">的元素都放在结果为</span>
false
<span style="font-family: 宋体;">的元素之前。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">prev_permutation</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：取出范围内的序列并将它重新排序为上一个序列。如果不存在上一个序列则返回</span>
false
<span style="font-family: 宋体;">。重载版本使用自定义的比较操作。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">random_shuffle</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：对范围内的元素随机调整次序。重载版本输入一个随机数产生操作。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">remove</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：删除在范围内的所有等于指定的元素，注意，该函数并不真正删除元素。内置数组不适合使用</span>
remove
<span style="font-family: 宋体;">和</span>
remove_if
<span style="font-family: 宋体;">函数。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">remove_copy</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：将所有不匹配的元素都复制到一个指定容器，返回的</span>
OutputIterator
<span style="font-family: 宋体;">指向被拷贝的末元素的下一个位置。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">remove_if</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：删除所有范围内输入操作结果为</span>
true
<span style="font-family: 宋体;">的元素。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">remove_copy_if</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：将所有不匹配的元素拷贝到一个指定容器。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">replace</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：将范围内的所有等于</span>
old_value
<span style="font-family: 宋体;">的元素都用</span>
new_value
<span style="font-family: 宋体;">替代。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">replace_copy</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：与</span>
replace
<span style="font-family: 宋体;">类似，不过将结果写入另外一个容器。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">replace_if</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：将范围内的所有操作结果为</span>
true
<span style="font-family: 宋体;">的元素用新值替代。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">replace_copy_if</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：类似与</span>
replace_if
<span style="font-family: 宋体;">，不过将结果写入另外一个容器。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">reverse</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：将范围内元素重新按反序排列。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">reverse_copy</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：类似与</span>
reverse
<span style="font-family: 宋体;">，不过将结果写入另外一个容器。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">rotate</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：将范围内的元素移到容器末尾，由</span>
middle
<span style="font-family: 宋体;">指向的元素成为容器第一个元素。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">rotate_copy</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：类似与</span>
rotate
<span style="font-family: 宋体;">，不过将结果写入另外一个容器。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">search</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：给出了两个范围，返回一个</span>
iterator
<span style="font-family: 宋体;">，指向在范围内第一次出现子序列的位置。重载版本使用自定义的比较操作。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">search_n</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：在范围内查找</span>
value
<span style="font-family: 宋体;">出现</span>
n
<span style="font-family: 宋体;">次的子序列。重载版本使用自定义的比较操作。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">set_difference</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：构造一个排过序的序列，其中的元素出现在第一个序列中，但是不包含在第二个序列中。重载版本使用自定义的比较操作。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">set_intersection</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：构造一个排过序的序列，其中的元素在两个序列中都存在。重载版本使用自定义的比较操作。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">set_symmetric_difference</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：构造一个排过序的序列，其中的元素在第一个序列中出现，但是不出现在第二个序列中。重载版本使用自定义的比较操作。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">set_union</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：构造一个排过序的序列，它包含两个序列中的所有的不重复元素。重载版本使用自定义的比较操作。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">sort</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：以升序重新排列范围内的元素，重载版本使用了自定义的比较操作。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">stable_partition</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：与</span>
partition
<span style="font-family: 宋体;">类似，不过它不保证保留容器中的相对顺序。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">stable_sort</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：类似与</span>
sort
<span style="font-family: 宋体;">，不过保留相等元素之间的顺序关系。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">swap</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：交换存储在两个对象中的值。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">swap_range</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：将在范围内的元素与另外一个序列的元素值进行交换。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">transform</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：将输入的操作作用在范围内的每个元素上，并产生一个新的序列。重载版本将操作作用在一对元素上，另外一个元素来自输入的另外一个序列。结果输出到指定的容器。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">unique</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：清除序列中重复的元素，和</span>
remove
<span style="font-family: 宋体;">类似，它也不能真正的删除元素。重载版本使用了自定义的操作。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">unique_copy</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：类似与</span>
unique
<span style="font-family: 宋体;">，不过它把结果输出到另外一个容器。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">upper_bound</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：返回一个</span>
iterator
<span style="font-family: 宋体;">，它指向在范围内的有序序列中插入</span>
value
<span style="font-family: 宋体;">而不破坏容器顺序的最后一个位置，该位置标志了一个大于</span>
value
<span style="font-family: 宋体;">的值。重载版本使用了输入的比较操作。</span>
</font>
</font>
<span>
<br />
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">堆算法：</span>
C++
<span style="font-family: 宋体;">标准库提供的是</span>
max-heap
<span style="font-family: 宋体;">。一共由以下</span>
4
<span style="font-family: 宋体;">个泛型堆算法。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">make_heap</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：把范围内的元素生成一个堆。重载版本使用自定义的比较操作。</font>
</span>
<span>
<br />
<strong>
<font face="Tahoma" size="2">pop_heap</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：并不是真正的把最大元素从堆中弹出，而是重新排序堆。它把</span>
first
<span style="font-family: 宋体;">和</span>
last-1
<span style="font-family: 宋体;">交换，然后重新做成一个堆。可以使用容器的</span>
back
<span style="font-family: 宋体;">来访问被&#8220;弹出&#8220;的元素或者使用</span>
pop_back
<span style="font-family: 宋体;">来真正的删除。重载版本使用自定义的比较操作。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">push_heap</font>
</strong>
</span>
<font face="Tahoma">
<font size="2">
<span style="font-family: 宋体;">：假设</span>
first
<span style="font-family: 宋体;">到</span>
last-1
<span style="font-family: 宋体;">是一个有效的堆，要被加入堆的元素在位置</span>
last-1
<span style="font-family: 宋体;">，重新生成堆。在指向该函数前，必须先把元素插入容器后。重载版本使用指定的比较。</span>
</font>
</font>
<span>
<br />
<strong>
<font face="Tahoma" size="2">sort_heap</font>
</strong>
</span>
<span style="font-family: 宋体;">
<font face="Tahoma" size="2">：对范围内的序列重新排序，它假设该序列是个有序的堆。重载版本使用自定义的比较操作。</font>
</span>
</font></font></font></font></font></font></font></font></font></font></p>
<p>
<font size="3"><font size="3"><font><font size="3"><font><font size="3"><font><font size="3"><font>				<font style="background-color: #ff0099;">接下来： STL容器学习
</font></font></font></font></font></font></font></font></font></font></p>
<img src ="http://www.blogjava.net/tinysun/aggbug/330074.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-08-27 16:11 <a href="http://www.blogjava.net/tinysun/archive/2010/08/27/330074.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>STL 迭代器</title><link>http://www.blogjava.net/tinysun/archive/2010/08/27/330072.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Fri, 27 Aug 2010 07:55:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/08/27/330072.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/330072.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/08/27/330072.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/330072.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/330072.html</trackback:ping><description><![CDATA[<p><font color="#ff0000">&lt;iterator&gt; 中定义了迭代器得使用方法，主要得模版类有：</font></p>
<p><font color="#ff0000"> 插入迭代器</font></p>
<p><font color="#ff0000">插入迭代器是一种迭代器适配器，带有一个容器参数，并生成一个迭代器，用于在指定的容器中插入元素。通过插入迭代器赋值时，迭代器将会插入一个新的元素。C++语言提供了三种插入器，其差别在于插入元素的位置不同：</font></p>
<div><font color="#ff0000">back_inserter，创建使用push_back实现插入的迭代器，其使用一个对象作为实参将一个新元素插入到容器得后端</font></div>
<div><font color="#ff0000">front_inserter的操作类似于back_inserter：该函数将创建一个迭代器，调用它所关联的基础容器的push_front成员函数代替赋值操作。</font></div>
<div><font color="#ff0000">注意：只有当容器提供push_front操作时，才能使用front_inserter。在vector或其他没有push_front运算的容器上使用front_inserter，将产生错误。</font></div>
<div><font color="#ff0000">inserter使用insert实现插入操作，inserter还带有第二个实参：指向插入起始位置的迭代器，inserter总是在它的迭代器参数所标明的位置前面插入新元素。</font></div>
<div><font color="#ff0000">流迭代器</font></div>
<div><font color="#ff0000">虽然iostream类型不是容器，但标准库同样提供了在iostream对象上使用的迭代
器：istream_iterator用于读取读入流，而ostream_iterator用于写输出流。这些迭代器将它们所对应的流视为特定类型的元素
序列。使用流迭代器时，可以用泛型算法从流对象中读数据（或将数据写到流对象中）。 </font>
<div>
<table style="width: 554px; height: 87px;" width="554" border="1" cellpadding="1" cellspacing="1">
    <tbody>
        <tr>
            <td><font color="#ff0000"> istream_iterator&lt;T&gt; in(strm);</font></td>
            <td><font color="#ff0000"> 创建从输入流strm中读取T类型对象的istream_iterator对象，strm是一个输入流</font></td>
        </tr>
        <tr>
            <td><font color="#ff0000"> istream_iterator&lt;T&gt; in;</font></td>
            <td><font color="#ff0000"> istream_iterator对象的超出末端迭代器</font></td>
        </tr>
        <tr>
            <td><font color="#ff0000"> ostream_iterator&lt;T&gt; out(strm);</font></td>
            <td><font color="#ff0000"> 创建将T类型的对象写到输出流strm的ostream_iterator对象</font></td>
        </tr>
        <tr>
            <td><font color="#ff0000"> ostream_iterator&lt;T&gt; out(strm, delim);</font></td>
            <td><font color="#ff0000"> 创建将T类型的对象写到输出流strm的ostream_iterator对象，在写入过程中使用delim作为元素的分隔符。delim是以空字符结束的字符数组</font></td>
        </tr>
    </tbody>
</table>
</div>
<div><font color="#ff0000">&nbsp;&nbsp;  流迭代器只定义了最基本的迭代器操作：自增、引用和赋值。此外，可比较两个istream迭代器是否相等（或不等）。而ostream迭代器则不提供比较运算。</font></div>
<div><font color="#ff0000"> 流迭代器的限制： </font>
<div><font color="#ff0000">（1）不可能从ostream_iterator对象读入，也不可能写到istream_iterator对象中；</font></div>
<div><font color="#ff0000">（2）一旦给ostream_iterator对象赋了一个值，写入就提交了。赋值后，没有办法再改变这个值。此外，ostream_iterator对象中每个不同的值都只能正好输出一次。</font></div>
<div><font color="#ff0000">（3）ostream_iterator没有-&gt;操作符。</font></div>
<div><font color="#ff0000">测试：</font></div>
<div>
<p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;"><font face="新宋体"><span style="color: #0000cc;"><span style="color: #000000;"><font face="新宋体"><font color="#ff0000"><span style="color: #0000cc;">#</span><span style="color: #ff0000;">include</span> <span style="color: #0000cc;">&lt;</span><span style="color: #ff0000;">iostream</span><span style="color: #0000cc;">&gt;</span><br />
<span style="color: #0000cc;">#</span><span style="color: #ff0000;">include</span> <span style="color: #0000cc;">&lt;</span><span style="color: #ff0000;">vector</span><span style="color: #0000cc;">&gt;</span><br />
<span style="color: #0000cc;">#</span><span style="color: #ff0000;">include</span> <span style="color: #0000cc;">&lt;</span><span style="color: #ff0000;">iterator</span><span style="color: #0000cc;">&gt;</span><br />
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> <span style="color: #ff0000;">std</span><span style="color: #0000cc;">;</span><br />
<br />
<span style="color: #0000ff;">int</span> main<span style="color: #0000cc;">(</span><span style="color: #0000cc;">)</span> <span style="color: #0000cc;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">istream_iterator</span><span style="color: #0000cc;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #0000cc;">&gt;</span> in_iter<span style="color: #0000cc;">(</span><span style="color: #ff0000;">cin</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">istream_iterator</span><span style="color: #0000cc;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #0000cc;">&gt;</span> <span style="color: #ff0000;">eof</span><span style="color: #0000cc;">;</span><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</font></font><font face="新宋体"><font color="#ff0000"><span style="color: #ff9900;">//vector&lt;int&gt; vec(in_iter, eof); //do the same work as following loop<br />
</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">vector</span><span style="color: #0000cc;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #0000cc;">&gt;</span> vec<span style="color: #0000cc;">;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span> <span style="color: #0000cc;">(</span>in_iter <span style="color: #0000cc;">!</span><span style="color: #0000cc;">=</span> <span style="color: #ff0000;">eof</span><span style="color: #0000cc;">)</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vec<span style="color: #0000cc;">.</span>push_back<span style="color: #0000cc;">(</span><span style="color: #0000cc;">*</span>in_iter<span style="color: #0000cc;">+</span><span style="color: #0000cc;">+</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">; //*in_iter可以取出输入流中得元素</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">vector</span><span style="color: #0000cc;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #0000cc;">&gt;</span><span style="color: #0000cc;">:</span><span style="color: #0000cc;">:</span><span style="color: #ff0000;">const_iterator</span> it <span style="color: #0000cc;">=</span> vec<span style="color: #0000cc;">.</span>begin<span style="color: #0000cc;">(</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span><span style="color: #0000cc;">(</span><span style="color: #0000cc;">;</span> it <span style="color: #0000cc;">!</span><span style="color: #0000cc;">=</span> vec<span style="color: #0000cc;">.</span>end<span style="color: #0000cc;">(</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span> <span style="color: #0000cc;">+</span><span style="color: #0000cc;">+</span>it<span style="color: #0000cc;">)</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">cout</span><span style="color: #0000cc;">&lt;</span><span style="color: #0000cc;">&lt;</span><span style="color: #0000cc;">*</span>it<span style="color: #0000cc;">&lt;</span><span style="color: #0000cc;">&lt;</span><span style="color: #ff0000;">endl</span><span style="color: #0000cc;">;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span> 0<span style="color: #0000cc;">;</span><br />
<span style="color: #0000cc;">}</span></font></font></span></span></font></span></code></p>
<p style="margin: 5px; line-height: 150%;"><code><span style="color: #000000;"><font face="新宋体"><font color="#ff0000"><span style="color: #0000cc;">#</span><span style="color: #ff0000;">include</span> <span style="color: #0000cc;">&lt;</span><span style="color: #ff0000;">iostream</span><span style="color: #0000cc;">&gt;</span><br />
<span style="color: #0000cc;">#</span><span style="color: #ff0000;">include</span> <span style="color: #0000cc;">&lt;</span><span style="color: #ff0000;">iterator</span><span style="color: #0000cc;">&gt;</span><br />
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> <span style="color: #ff0000;">std</span><span style="color: #0000cc;">;</span><br />
<br />
<span style="color: #0000ff;">int</span> main<span style="color: #0000cc;">(</span><span style="color: #0000cc;">)</span> <span style="color: #0000cc;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">ostream_iterator</span><span style="color: #0000cc;">&lt;</span><span style="color: #ff0000;">string</span><span style="color: #0000cc;">&gt;</span> out_iter<span style="color: #0000cc;">(</span><span style="color: #ff0000;">cout</span><span style="color: #0000cc;">,</span> <span style="color: #ff00ff;">""n"</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">istream_iterator</span><span style="color: #0000cc;">&lt;</span><span style="color: #ff0000;">string</span><span style="color: #0000cc;">&gt;</span> in_iter<span style="color: #0000cc;">(</span><span style="color: #ff0000;">cin</span><span style="color: #0000cc;">)</span><span style="color: #0000cc;">,</span> <span style="color: #ff0000;">eof</span><span style="color: #0000cc;">;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span> <span style="color: #0000cc;">(</span>in_iter <span style="color: #0000cc;">!</span><span style="color: #0000cc;">=</span> <span style="color: #ff0000;">eof</span><span style="color: #0000cc;">)</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000cc;">*</span>out_iter<span style="color: #0000cc;">+</span><span style="color: #0000cc;">+</span> <span style="color: #0000cc;">=</span> <span style="color: #0000cc;">*</span>in_iter<span style="color: #0000cc;">+</span><span style="color: #0000cc;">+</span><span style="color: #0000cc;">;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span> 0<span style="color: #0000cc;">;</span><br />
<span style="color: #0000cc;">}</span></font></font></span></code></p>
<code><span style="color: #000000;"><font face="新宋体"><span style="color: #0000cc;">
<div><font color="#ff0000">反向迭代器</font></div>
<div><font color="#ff0000">反向迭代器是一种反向遍历容器的迭代器。也就是，从最后一个元素到第一个元素遍历容器。反向迭代器将自增（和自减）的含义反过来了：对于反向迭代器，++运算将访问前一个元素，而--运算则访问下一个元素。</font></div>
<div><font color="#ff0000">（1）反向迭代器需要使用自减操作符：标准容器上的迭代器（reverse_iterator)既支持自增运算，也支持自减运算。但是，流迭代器由于不能反向遍历流，因此流迭代器不能创建反向迭代器。</font>
<div><font color="#ff0000">（2）可以通过reverse_iterator::base()将反向迭代器转换为普通迭代器使用，从逆序得到普通次序。</font></div>
<div><font color="#ff0000">测试：</font></div>
<div><font color="#ff0000">#include &lt;iostream&gt;<br />
#include &lt;string&gt;<br />
#include &lt;iterator&gt;<br />
#include &lt;algorithm&gt;<br />
using namespace std;</font></div>
<div><font color="#ff0000">int main() {<br />
&nbsp;&nbsp;&nbsp;  string str = "this 'sentence' is a test";<br />
&nbsp;&nbsp;&nbsp;  cout&lt;&lt;str&lt;&lt;endl;<br />
&nbsp;&nbsp;&nbsp;  <br />
&nbsp;&nbsp;&nbsp;  string::iterator it1 = find(str.begin(), str.end(), '"'');<br />
&nbsp;&nbsp;&nbsp;  string::iterator it2 = find(++it1, str.end(), '"'');<br />
&nbsp;&nbsp;&nbsp;  cout&lt;&lt;string(it1, it2)&lt;&lt;endl; <br />
&nbsp;&nbsp;&nbsp;  <br />
&nbsp;&nbsp;&nbsp;  string::reverse_iterator rit1 = find(str.rbegin(), str.rend(), '"'');<br />
&nbsp;&nbsp;&nbsp;  string::reverse_iterator rit2 = find(++rit1, str.rend(), '"'');<br />
&nbsp;&nbsp;&nbsp;  cout&lt;&lt;string(rit1, rit2)&lt;&lt;endl;<br />
&nbsp;&nbsp;&nbsp;  cout&lt;&lt;string(rit2.base(), rit1.base())&lt;&lt;endl;<br />
&nbsp;&nbsp;&nbsp;  getchar();<br />
&nbsp;&nbsp;&nbsp;  return 0;<br />
}</font></div>
<div><font color="#ff0000">不同的迭代器支持不同的操作集，而各种算法也要求相应的迭代器具有最小的操作集。因此，可以将算法的迭代器分为下面五类：</font>
<div>
<table style="width: 562px; height: 108px;" width="562" border="1" cellpadding="1" cellspacing="1">
    <tbody>
        <tr>
            <td><font color="#ff0000"> 输入迭代器<br />
            (input iterator)</font></td>
            <td><font color="#ff0000"> 读，不能写。支持的操作集：==, !=, 前缀++, 后缀++, *, -&gt;。例如，find, accumulate算法要求这类迭代器。</font></td>
        </tr>
        <tr>
            <td><font color="#ff0000"> 输出迭代器<br />
            (output iterator)</font></td>
            <td><font color="#ff0000"> 写，不能读。支持的操作集：前缀++, 后缀++, *（只能出现在赋值运算的左操作数上)。推出迭代器要求每个迭代器必须正好写入一次。例如，ostream_iterator是输出迭代器，copy算法使用这类迭代器。</font></td>
        </tr>
        <tr>
            <td><font color="#ff0000"> 前向迭代器(forward iterator)</font></td>
            <td><font color="#ff0000"> 读和写，支持输入迭代器和输出迭代器提供的所有操作，还支持对同一个元素的多次读写。例如，replace算法需要这种迭代器。</font></td>
        </tr>
        <tr>
            <td><font color="#ff0000"> 双向迭代器(bidirectional iterator)</font></td>
            <td><font color="#ff0000"> 读和写，除了支持前向迭代器的所有操作，还支持前缀--和后缀--，即支持双向遍历容器。例如，reverse算法要求这类迭代器。标准库容器中提供的迭代器都至少达到双向迭代器的要求。</font></td>
        </tr>
        <tr>
            <td><font color="#ff0000"> 随机访问迭代器(random-access iterator)</font></td>
            <td><font color="#ff0000">
            读和写。提供在常量时间内访问容器任意位置的功能。支持完整的迭代器操作集：1）关系运算：==, !=, &lt;, &lt;=, &gt;,
            &gt;=；2）算术运算：it + n, it - n, it += n, it -= n以及it1 -
            it2；3）下标运算：it[n]，等价于*(it + n)。需要随机访问迭代器的泛型算法包括sort算法。例如，vector, deque,
            string迭代器是随机访问迭代器，用作访问内置数组元素的指针也是随机访问迭代器。</font></td>
        </tr>
    </tbody>
</table>
</div>
<div><font color="#ff0000">&nbsp;&nbsp;
除了输出迭代器，其他类别的迭代器形成了一个层次结构：需要低级类别迭代器的地方，可使用任意一种更高级的迭代器。例如，对于需要输入迭代器的算法，可传
递前向、双向或随机访问迭代器调用该算法。而反之则不行。注意：向算法传递无效的迭代器类别所引起的错误，无法保证会在编译时被捕获到。</font></div>
<div><font color="#ff0000">&nbsp;&nbsp;  map, set, list类型提供双向迭代器，而string,
vector和deque容器上定义的迭代器都是随机访问迭代器，用作访问内置数组元素的指针也是随机访问迭代器。istream_iterator是输
入迭代器，ostream_iterator是输出迭代器。</font></div>
<div><font color="#ff0000">&nbsp;&nbsp;
另外，虽然map和set类型提供双向迭代器，但关联容器只能使用这部分算法的一个子集。因为关联容器的键是const对象。因此，关联容器不能使用任何
写序列元素的算法。只能使用与关联容器绑在一起的迭代器来提供用于读操作的实参。因此，在处理算法时，最好将关联容器上的迭代器视为支持自减运算的输入迭
代器，而不是完整的双向迭代器。</font></div>
</div>
</div>
</span></font></span></code></div>
</div>
</div>
<img src ="http://www.blogjava.net/tinysun/aggbug/330072.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-08-27 15:55 <a href="http://www.blogjava.net/tinysun/archive/2010/08/27/330072.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> c++对象模型系列 转</title><link>http://www.blogjava.net/tinysun/archive/2010/08/26/329947.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 26 Aug 2010 02:52:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/08/26/329947.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/329947.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/08/26/329947.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/329947.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/329947.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp; 一、指针与引用一 概括指针和引用，在C++的软件开发中非常常见，如果能恰当的使用它们能够极大的提高整个软件的效率，但是很多的C++学习者对它们的各种使用情况并不是都了解，这就导致了实际的软件开发中经常会内存泄漏，异常抛出，程序崩溃等问题。对于C和C++的初学者，那更是被它们搞的迷迷糊糊。本篇作为[深入C++]系列的第一节，我们就带领大家把指针和引用这个...&nbsp;&nbsp;<a href='http://www.blogjava.net/tinysun/archive/2010/08/26/329947.html'>阅读全文</a><img src ="http://www.blogjava.net/tinysun/aggbug/329947.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-08-26 10:52 <a href="http://www.blogjava.net/tinysun/archive/2010/08/26/329947.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>small or big edian</title><link>http://www.blogjava.net/tinysun/archive/2010/08/23/329623.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Mon, 23 Aug 2010 02:13:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/08/23/329623.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/329623.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/08/23/329623.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/329623.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/329623.html</trackback:ping><description><![CDATA[<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><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;">stdio.h</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;"><br />
</span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;main()<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: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;union<br />
</span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
</span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">short</span><span style="color: #000000;">&nbsp;s;<br />
</span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;c[</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(</span><span style="color: #0000ff;">short</span><span style="color: #000000;">)];<br />
</span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}un;<br />
</span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;un.s</span><span style="color: #000000;">=</span><span style="color: #000000;">0x0102</span><span style="color: #000000;">;<br />
</span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(un.c[</span><span style="color: #000000;">0</span><span style="color: #000000;">]</span><span style="color: #000000;">==</span><span style="color: #000000;">0x01</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">big&nbsp;edian!\n</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">14</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(un.c[</span><span style="color: #000000;">1</span><span style="color: #000000;">]</span><span style="color: #000000;">==</span><span style="color: #000000;">0x02</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">15</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">small&nbsp;edian!\n</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br />
</span><span style="color: #008080;">17</span>&nbsp;<span style="color: #000000;">}</span></div>
<img src ="http://www.blogjava.net/tinysun/aggbug/329623.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-08-23 10:13 <a href="http://www.blogjava.net/tinysun/archive/2010/08/23/329623.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅谈setjmp与longjmp 转</title><link>http://www.blogjava.net/tinysun/archive/2010/08/06/328121.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Fri, 06 Aug 2010 05:29:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/08/06/328121.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/328121.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/08/06/328121.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/328121.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/328121.html</trackback:ping><description><![CDATA[<font size="1">在C语言中，用于跳转的goto语句，只能够用在同一个函数内部的跳转。而setjmp 与 longjmp的结合使用，却可以实现在不同程序之间的跳转。让我们先来看一下函数原型吧：<br />
</font>
<table class="allBorders" width="641" border="1" cellpadding="5" cellspacing="0" height="128" rules="none">
    <tbody>
        <tr>
            <td class="docTableCell" valign="top" align="left">
            <pre><font size="1">#include &lt;setjmp.h&gt;<br />
            int setjmp(jmp_buf <span class="docEmphItalicAlt">env</span>）</font></pre>
            </td>
        </tr>
        <tr>
            <td class="docTableCell" valign="top" align="right">
            <div align="left"> </div>
            <div align="left"><font size="1">Returns: 0 if called directly, nonzero if returning from a call to <tt><font face="新宋体">longjmp.</font></tt></font></div>
            <p class="docText"> </p>
            </td>
        </tr>
        <tr align="left">
            <td class="docTableCell" valign="top">
            <pre><font size="1">void longjmp(jmp_buf <span class="docEmphItalicAlt">env</span>, int <span class="docEmphItalicAlt">val</span>);</font></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<font size="1">&nbsp;&nbsp;&nbsp;  这两个函数都要包含头文件setjmp.h。而且它们在处理出现在深层函数嵌套的错误情况时很有用处。<br />
&nbsp;&nbsp;&nbsp;  setjmp这个函数很有意思，虽然是一个函数，可是却可以返回两个不同的值。当第一次直接调用setjmp时，返回值为0。当从longjmp函数返回时，setjmp函数的返回值为longjmp的第二个参数的值。<br />
&nbsp;&nbsp;&nbsp;  那么在什么地方调用setjmp呢？我们希望当从longjmp函数返回时，程序从哪里接着开始运行，我们就在哪里调用setjmp。看个小实例，你就明白是怎么回事了。<br />
<br />
&nbsp;&nbsp;&nbsp;  #include&lt;stdio.h&gt;<br />
&nbsp;&nbsp;&nbsp;  #include&lt;setjmp.h&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;  jmp_buf ebuf;<br />
&nbsp;&nbsp;&nbsp;  void f2(void);<br />
&nbsp;&nbsp;  int main(void)<br />
&nbsp;&nbsp;  {<br />
&nbsp;&nbsp;&nbsp;&nbsp;  int i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;  printf("1");<br />
&nbsp;&nbsp;&nbsp;&nbsp;  i=setjmp(ebuf);<br />
&nbsp;&nbsp;&nbsp;&nbsp;  if(i==0)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //第一次执行到这里时，值为0，所以接下来执行f2()<br />
&nbsp;&nbsp;&nbsp;&nbsp;  {<br />
&nbsp;&nbsp;  f2();<br />
&nbsp;&nbsp;  printf("This will not be printed."); <br />
&nbsp;&nbsp;&nbsp;&nbsp;  }<br />
&nbsp;&nbsp;&nbsp;&nbsp;  printf("%d",i);&nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  //由于从longjmp返回时，i=3，不执行if，所以执行该行<br />
&nbsp;&nbsp;&nbsp;&nbsp;  return 0;<br />
}<br />
&nbsp;&nbsp;  void f2(void)<br />
{<br />
&nbsp;&nbsp;  printf("2");&nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  <br />
&nbsp;&nbsp;  longjmp(ebuf,3);&nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  &nbsp;&nbsp;  //longjmp函数返回，回到setjmp的位置，使得setjmp返回值为3<br />
} <br />
&nbsp;&nbsp;&nbsp;  函数最后的执行结果为123，嘻嘻。</font>
<p><font size="1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  longjmp注意：<br />
1.不要假象寄存器类型的变量将总会保持不变。在调用longjmp之后，通过setjmp所返回的控制流中，例程中寄存器类型的变量将不会被恢复。<br />
2.不要使用longjmp函数来实现把控制流，从一个中断处理例程中传出，除非被捕获的异常是一个浮点数异常。在后一种情况下，如果程序通过调用 _fpreset函数，来首先初始化浮点数包后，它是可以通过longjmp来实现从中断处理例程中返回。<br />
3.
在C++程序中，小心对setjmp和longjmp的使用，应为setjmp和longjmp并不能很好地支持C++中面向对象的语义。因此在C++程
序中，使用C++提供的异常处理机制将会更加安全。把setjmp和longjmp组合起来，原来它这么厉害！</font></p>
<img src ="http://www.blogjava.net/tinysun/aggbug/328121.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-08-06 13:29 <a href="http://www.blogjava.net/tinysun/archive/2010/08/06/328121.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>析构函数 构造函数</title><link>http://www.blogjava.net/tinysun/archive/2010/08/06/328118.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Fri, 06 Aug 2010 04:58:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/08/06/328118.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/328118.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/08/06/328118.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/328118.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/328118.html</trackback:ping><description><![CDATA[关于初始化列表，它在构造函数的函数体之前执行。<br />
关于继承，子类的构造函数在自身函数体执行之前调用父类的构造函数，子类的析构函数会在自身的函数体执行之后调用父类的析构函数。<br />
关
于多态，有虚函数的类的对象中会在最前面多出4个字节来作为虚表指针，父类的构造函数会设置对象的虚表指针指向父类的虚函数表，然后这个类的构造函数会重
新设置对象的虚表指针指向这个类的虚函数表，这个类的析构函数会再次设置对象的虚表指针指向这个类的虚函数表，最后调用父类的析构函数又会重新设置对象的
虚表指针指向父类的虚函数表，所以在构造和析构函数中即使调用虚函数也不会有多态发生。但是构造完毕之后析构之前，调用虚函数则会通过对象的虚表指针找到
虚函数表来调用，多态可以正常工作。<br />
关于new/delete，new是先分配空间再调用构造函数，delete会先调用析构函数再释放空间。如果是虚析构，看下一条。<br />
关于虚析构，实际上析构不是虚函数，用一个虚函数scalar_deleting_destructor来替代，它会先调用析构函数，然后根据传入的参数是否（最低位）是1来决定是否用delete释放空间。
<img src ="http://www.blogjava.net/tinysun/aggbug/328118.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-08-06 12:58 <a href="http://www.blogjava.net/tinysun/archive/2010/08/06/328118.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学会用core dump调试程序错误</title><link>http://www.blogjava.net/tinysun/archive/2010/07/29/327453.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 29 Jul 2010 08:21:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/07/29/327453.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/327453.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/07/29/327453.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/327453.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/327453.html</trackback:ping><description><![CDATA[，一直不知道用core dump工具来调试程序，花了近一周的时间，才定位问题，老大很生气，后果很严重，呵呵，事后仔细学习了这块的知识，了解一点core dump的知识。
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在使用半导体作为内存的材料前，人类是利用线圈当作内存的材料（发明者为王安），线圈就叫作core ，用线圈做的内存就叫作&#8220;core
memory&#8221;。（线圈的单词应该是coil，呵呵）如今，半导体工业澎勃发展，已经没有人用线圈当内存了，不过，在许多情况下，人们还是把内存叫作&#8220;core&#8221;。
所以注意了：这里的core不是核心，而是内存。不过结合实际来看，好像也有点&#8220;内核所占内存&#8221;的意思。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; core dump又是什么东东？<strong>   </strong>我
们在开发（或使用）一个程序时，最怕的就是程序莫明其妙地挂掉。虽然系统没事，但我们下次仍可能遇到相同的问题。于是，这时操作系统就会把程序挂掉时的
内存内容写入一个叫做core的文件里（这个写入的动作就叫dump，dump的英语意思是垃圾、倾倒。从这里来看，这些内存的内容是程序错误运行的结
果，所以算是垃圾，把他弄出来就好比从大的内存池里&#8220;倾倒&#8221;。），以便于我们调试。这个过程，因此叫做core dump。     </p>
<p>1. 在嵌入式系统中，有时core dump直接从串口打印出来，<span style="color: #0000ff;"><span style="color: #000000;">结合objdump查找ra和epa地址，运用栈回溯，可以找到程序出错的地方。</span></span></p>
<p><span style="color: #0000ff;"><span style="color: #000000;">2.
在一般Linux系统中，默认是不会产生core dump文件的，通过ulimit -c来查看core
dump文件的大小，一般开始是0，可以设置core文件大小，ulimit -c 1024(kbytes单位)或者ulimit -c
unlimited。</span></span></p>
<p><span style="color: #0000ff;"><span style="color: #000000;">3. core dump文件输出设置，一般默认是当前目录，可以在/proc/sys/kernel中找<code>到core-user-pid，通过</code></span></span></p>
<p><span style="color: #0000ff;"><span style="color: #000000;">echo </span></span><span style="color: #0000ff;"><span style="color: #000000;">"1" &gt; /proc/sys/kernel/core-user-pid使core文件名加上pid号，还可以用</span></span></p>
<p><span style="color: #0000ff;"><span style="color: #000000;">mkdir -p /root/corefile<br />
</span></span></p>
<p><span style="color: #0000ff;"><span style="color: #000000;">echo "/root/corefile/core-%e-%p-%t" &gt; /proc/sys/kernel/core-pattern</span></span><code style="margin: 0px;" dir="ltr">控制core文件保存位置和文件名格式。</code></p>
<p><code style="margin: 0px;" dir="ltr">以下是参数列表:<br />
&nbsp; &nbsp; %p - insert pid into filename 添加pid<br />
&nbsp; &nbsp; %u - insert current uid into filename 添加当前uid<br />
&nbsp; &nbsp; %g - insert current gid into filename 添加当前gid<br />
&nbsp; &nbsp; %s - insert signal that caused the coredump into the filename 添加导致产生core的信号<br />
&nbsp; &nbsp; %t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间<br />
&nbsp; &nbsp; %h - insert hostname where the coredump happened into filename 添加主机名<br />
&nbsp; &nbsp; %e - insert coredumping executable name into filename 添加命令名<br />
</code></p>
<p><span style="color: #0000ff;"><span style="color: #000000;">4. </span></span><code style="margin: 0px;" dir="ltr">用gdb查看core文件:<br />
下面我们可以在发生运行时信号引起的错误时发生core dump了.编译时加上-g<br />
发生core dump之后, 用gdb进行查看core文件的内容, 以定位文件中引发core dump的行.<br />
gdb [exec file] [core file]<br />
如:<br />
gdb ./test test.core<br />
在进入gdb后, 用bt命令查看backtrace以检查发生程序运行到哪里, 来定位core dump的文件行.</code></p>
<p>5. 给个例子</p>
<p>test.c</p>
<p>void a()</p>
<p>{</p>
<p>&nbsp;&nbsp; char *p = NULL;</p>
<p>&nbsp;&nbsp; printf("%d\n", *p);</p>
<p>}</p>
<p>int main()</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp; a();</p>
<p>&nbsp;&nbsp;&nbsp; return 0;</p>
<p>}</p>
<p>编译 gcc -g -o test test.c</p>
<p>运行 ./test</p>
<p>报segmentation fault(core dump)</p>
<p>gdb ./test test.core如果生成的是test.core.</p>
<img src ="http://www.blogjava.net/tinysun/aggbug/327453.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-07-29 16:21 <a href="http://www.blogjava.net/tinysun/archive/2010/07/29/327453.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言的反汇编代码（BP，SP的关系） 转</title><link>http://www.blogjava.net/tinysun/archive/2010/07/29/327413.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 29 Jul 2010 03:41:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/07/29/327413.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/327413.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/07/29/327413.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/327413.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/327413.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1. 最简单的代码：//// test1.cint main(){&nbsp;&nbsp;&nbsp; return 1;}&nbsp;编译、反汇编：gcc test1.cgdb ./a.out(gdb) disassemble main&nbsp;0x08048344 &lt;main+0&gt;:&nbsp;&nbsp;&nbsp;&nbsp;&nb...&nbsp;&nbsp;<a href='http://www.blogjava.net/tinysun/archive/2010/07/29/327413.html'>阅读全文</a><img src ="http://www.blogjava.net/tinysun/aggbug/327413.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-07-29 11:41 <a href="http://www.blogjava.net/tinysun/archive/2010/07/29/327413.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>#if defined()的含义(ZZ)</title><link>http://www.blogjava.net/tinysun/archive/2010/07/27/327215.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Tue, 27 Jul 2010 06:22:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/07/27/327215.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/327215.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/07/27/327215.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/327215.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/327215.html</trackback:ping><description><![CDATA[<p>看到内核代码中有很多地方都使用了#if defined()，可是却找不到这个东东的定义，主要是define()。它和我们常用的#ifdef有什么不同吗？ </p>
<p>4.2.3
Defined The special operator defined is used in #if and #elif
expressions to test whether a certain name is defined as a macro.
defined name and defined (name) are both expressions whose value is 1 if
name is defined as a macro at the current point in the program, and 0
otherwise. Thus, #if defined MACRO is precisely equivalent to #ifdef
MACRO. </p>
<p>defined is useful when you wish to test more than one macro for existence at once. For example, </p>
<p>#if defined (__vax__) || defined (__ns16000__) </p>
<p>would succeed if either of the names __vax__ or __ns16000__ is defined as a macro. </p>
<p>Conditionals written like this: </p>
<p>#if defined BUFSIZE &amp;&amp; BUFSIZE &gt;= 1024 </p>
<p>can
generally be simplified to just #if BUFSIZE &gt;= 1024, since if
BUFSIZE is not defined, it will be interpreted as having the value zero.
</p>
If the defined operator appears as a result of a macro
expansion, the C standard says the behavior is undefined. GNU cpp treats
it as a genuine defined operator and evaluates it normally. It will
warn wherever your code uses this feature if you use the command-line
option -pedantic, since other compilers may handle it differently.
<img src ="http://www.blogjava.net/tinysun/aggbug/327215.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-07-27 14:22 <a href="http://www.blogjava.net/tinysun/archive/2010/07/27/327215.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>区分C语言中getch、getche、fgetc、getc、getchar、fgets、gets 转</title><link>http://www.blogjava.net/tinysun/archive/2010/07/26/327155.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Mon, 26 Jul 2010 09:34:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/07/26/327155.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/327155.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/07/26/327155.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/327155.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/327155.html</trackback:ping><description><![CDATA[<p><strong style="color: #ff6600;">首先，这两个函数不是C标准库中的函数，</strong></p>
<p>int getch(void)　　　　//从标准输入读入一个字符，当你用键盘输入的时候，屏幕不显示你所输入的字符。也就是，<span style="background-color: yellow;">不带回显。</span><br />
int getche(void) 　　　//从标准输入读入一个字符，键盘输入的时候，屏幕显示所输入的字符。<span style="background-color: yellow;">带回显。</span></p>
<p>这两个函数包含在头文件conio.h中，需要记住的是conio.h不是C标准库中的头文件。Micorsoft 和 Borland的
C编译器提供了conio.h，用来创建控制台文本用户界面。一般在Windows系统下安装了VS、VC等，就可以包含conio.h头文件。但是一般
在Unix、Linux系统中，/usr/include/中都没有这个头文件。</p>
<p><span style="color: #008080;"><u>getch和getche在等待用户从键盘输入的时候，用户按下一个键后，不需要按回车</u></span>，程序自动往下执行。在Linux中，终端输入在缺省情况下是被&#8220;一锅端&#8221;的，也就是说整行输入是被一起处理的。通常，这是一种人们所希望的方便的办法，但它也意味着在读入数据时必须按一下回车键表示输入行结束后才能得到输入的数据。在游戏中，很多都提供了&#8220;<span style="color: #ff00ff;"><strong>老板键</strong></span>&#8221;，它的实现，就是利用了这两个函数。</p>
<p>&nbsp;</p>
<p><span style="color: #ff6600; font-size: 10pt;"><strong>其次，除了getch和getche，其他的都是C标准库中的头文件，包含在头文件stdio.h中。</strong></span></p>
<pre style="padding: 0px; margin: 0px;"><span style="font-size: 10pt;">
<pre style="padding: 0px; margin: 0px;"><span style="font-size: 10pt;">int fgetc ( FILE * stream ); //从流stream中读一个字符。可以将标准输入stdin作为它的实参，这时候从标准输入读取一个字符。</span></pre>
</span></pre>
<pre style="padding: 0px; margin: 0px;"><span style="font-size: 10pt;">int getc(FILE * stream);     //和fgetc等效，由fgetc通过宏实现。</span></pre>
<pre style="padding: 0px; margin: 0px;">
<pre style="padding: 0px; margin: 0px;"><span style="font-size: 10pt;">int getchar ( void );　　　　 //从标准输入stdin读入一个字符，程序等待你输入的时候，你可以输入多个字符，回车后程序继续执行。</span></pre>
<pre style="padding: 0px; margin: 0px;"><span style="font-size: 10pt;">                                 //但getchar只读入一个字符</span></pre>
<pre style="padding: 0px; margin: 0px;"><span style="color: #000000; font-size: 10pt;"><strong>说明:getc、getchar都是通过宏定义借助fgetc实现。如getchar的实现为，#define getchar() fgetc(stdin)。</strong></span></pre>
<pre style="padding: 0px; margin: 0px;">&nbsp;</pre>
<pre style="padding: 0px; margin: 0px;">
<pre style="padding: 0px; margin: 0px;"><span style="font-size: 10pt;">char * fgets (char * str, int num, FILE *stream);</span></pre>
<pre style="padding: 0px; margin: 0px;"><span style="font-size: 10pt;">　　　　　　　　　　　　　　　　 //从流stream中读入最多num个字符到字符数组str中，当遇到换行符时、或读到num-1个字符时停止。</span></pre>
<pre style="padding: 0px; margin: 0px;"><span style="font-size: 10pt;">　　　　　　　　　　　　　　　　 //自动加上'\0'空字符结尾</span><span style="widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: medium Simsun; white-space: normal; orphans: 2; letter-spacing: normal; color: #000000; word-spacing: 0px;" class="Apple-style-span"></span></pre>
</pre>
</pre>
<pre style="padding: 0px; margin: 0px;"><span style="color: #000000; font-size: 10pt;">char * gets ( char * str );　</span><span style="color: #000000; font-size: 10pt;">//从标准输入stdin读取一个字符串，遇到换行或结束时候终止。</span></pre>
<pre style="padding: 0px; margin: 0px;"><span style="color: #000000; font-size: 10pt;">　　　　　　　　　　　　　　　　 //</span><span style="color: #000000; font-size: 10pt;">不同于fgets，他没有指定num，所以需要注意字符数组str的大小。</span></pre>
<pre style="padding: 0px; margin: 0px;">&nbsp;</pre>
<pre style="padding: 0px; margin: 0px;"><span style="color: #000000; font-size: 10pt;">说明：</span>&nbsp;fgets和gets之间没有宏定义的关系，彼此各自有自己的实现。蠕虫病毒的实现就是函数gets的&#8220;功劳&#8221;。gets函数的任务是从流中读入一个字符串。它的调用者会告诉它把读入的字符串放在什么地方。但是，gets()函数并不检查缓冲区大小，如果调用者提供了一个指向堆栈的指针，并且get()函数读入的字符数量超过了超过了缓冲区的空间大小，get()会愉快地将多出来的字符继续写入到堆栈中，这就覆盖了堆栈中原来的内容。如：<br />
<div class="cnblogs_code">
<div><!--<br/ />
<br/ />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />
http://www.CodeHighlighter.com/<br/ />
<br/ />
--><span style="color: #000000;">main()<br />
{<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;line[</span><span style="color: #800080;">512</span><span style="color: #000000;">];&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">在程序的堆栈上分配512个字符的空间</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;...<br />
&nbsp;&nbsp;&nbsp;gets(line);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">蠕虫病毒的入口，可以将恶意代码通过多出来的数据写入堆栈</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">}</span></div>
</div>
<p>&nbsp;</p>
</pre>
<p>建议不要用getch和getche，因为它们不是C标准库中的函数。用它们写出的程序可移植性差，不同的编译器不保证可以包含conio.h。建议用fgets函数彻底替代gets函数。</p>
<p>&nbsp;</p>
<p><span style="color: #ff6600;"><strong>另外，绝大多数的这些get函数，都有对应的put版本。</strong></span></p>
<p><span style="font-family: Comic Sans MS;">int fputc ( int character, FILE * stream );</span></p>
<p><span style="font-family: Comic Sans MS;">int putc ( int character, FILE * stream );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //通过宏定义和fputc实现</span></p>
<p><span style="font-family: Comic Sans MS;">int putchar ( int character );　　　　　　　　//通过宏定义实现：#define putchar(c) fputc(c, stdout)</span></p>
<p><span style="color: #993300;"><strong></strong></span>&nbsp;</p>
<p><span style="color: #993300;"><span style="color: #993300;"><span style="font-family: Comic Sans MS; color: #000000;">int fputs ( const char * str, FILE * stream );</span></span></span></p>
<p><span style="color: #993300;"><span style="color: #993300;"><span style="font-family: Comic Sans MS; color: #000000;">int puts ( const char * str );</span></span></span></p>
<p><span style="color: #993300;"><span style="color: #993300;"><span style="font-family: Comic Sans MS; color: #000000;">说明：两者之间无宏定义实现关系。puts(const char *str)近似等效于fputs(cosnt char *str, stdout)，不同点是前者还输出一个'\n'</span></span></span></p>
<p>&nbsp;</p>
<p><span style="color: #ff6600;"><strong>最后，关于EOF</strong></span></p>
<p>EOF是在stdio.h文件中定义的符号常量，值为-1。如，</p>
<p><span style="font-family: Comic Sans MS;">fputc</span>函数返回一个值：如果输出成功则返回值就是输出的字符；如果输出失败，则返回一个EOF。&nbsp;</p>
<p><span style="font-family: Comic Sans MS;">fgetc函数读字符时遇到文件结束符，函数返回一个文件结束标记EOF。如果想从一个磁盘文件顺序读入字符并在屏幕上显示，可以：</span></p>
<div class="cnblogs_code">
<div><!--<br/ />
<br/ />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />
http://www.CodeHighlighter.com/<br/ />
<br/ />
--><span style="color: #000000;">ch&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;fgetc(fp);<br />
</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(ch&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;EOF){<br />
&nbsp;&nbsp;putchar(ch);<br />
&nbsp;&nbsp;ch&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;fgetc(fp);<br />
}</span></div>
</div>
<p>&nbsp;</p>
<p>注意，EOF不是可输出字符，因此不能在屏幕上显示。由于ASCII码不可能出现-1，因此EOF定义为-1是合适的。当读入的字符值等于-1（即
EOF）时，表示读入的已不是正常的字符，而是文件结束符。但以上只适用于读取文本文件的情况。现在ANSI C
已经允许用缓冲文件系统处理二进制文件，而读入某一个字节中的二进制数据的值有可能是-1，而这又恰好是EOF的值。这就出现了需要读入有用数据，却处理
为&#8220;文件结束&#8221;。feof(fp) 用来测试fp所指向的文件当前状态是否是&#8220;文件结束&#8221;。如果想顺序读入一个二进制文件数据，可以：</p>
<div class="cnblogs_code">
<div><!--<br/ />
<br/ />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />
http://www.CodeHighlighter.com/<br/ />
<br/ />
--><span style="color: #0000ff;">while</span><span style="color: #000000;">(</span><span style="color: #000000;">!</span><span style="color: #000000;">feof(fp)){<br />
&nbsp;&nbsp;&nbsp;c&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;fgetc(fp);<br />
&nbsp;&nbsp;&nbsp;...<br />
}&nbsp; <br />
</span></div>
</div>
<img src ="http://www.blogjava.net/tinysun/aggbug/327155.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-07-26 17:34 <a href="http://www.blogjava.net/tinysun/archive/2010/07/26/327155.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>小谈声明（Declaration）和定义（Definition） </title><link>http://www.blogjava.net/tinysun/archive/2010/06/03/322620.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 03 Jun 2010 06:11:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/06/03/322620.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/322620.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/06/03/322620.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/322620.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/322620.html</trackback:ping><description><![CDATA[声明（Declaration）用于说明每个标识符的含义，而并不必为每个标识符预存储空间。预留存储空间的声明称为定义（Definition）。声明的形式为：声明说明符 声明符声明符是由存储类说明符和类型说明符组成的。
<p><font size="3">1、变量的声明有两种情况： 一种是需要建立存储空间的。<br />
&nbsp;&nbsp; 例如：int a 在声明的时候就已建立了存储空间。 <br />
2、另一种是不必建立存储空间。<br />
&nbsp;&nbsp; 例如：extern int a 其中 变量a是在别的文件中定义的。</font></p>
<p><font size="3">例一： <br />
Declaration. <br />
A construct which associates attributes to a variable name or function. No storage is reserved. For example:<br />
extrn int a; <br />
extrn char c; <br />
variable declaration A structure decleration could look like: </font></p>
<p><font size="3"><font style="background-color: #3399ff"><font style="background-color: #6666cc" color="#ffffff"></font></font>&nbsp;</font><font size="3">Definition. <br />
Variable definition is a declaration with storage allocation. </font></p>
<p><font style="background-color: #66ccff" color="#000066">
<table style="width: 100%" cellspacing="1" cellpadding="1" border="1">
    <tbody>
        <tr>
            <td>
            <p><font style="background-color: #66ccff" color="#000000">struct per_rec<br />
            {&nbsp;<br />
            &nbsp;&nbsp;&nbsp; int age; <br />
            &nbsp;&nbsp;&nbsp; char *surname; <br />
            &nbsp;&nbsp;&nbsp; char *firstname;</font></p>
            <p><font style="background-color: #66ccff" color="#000000">}; </font></p>
            </td>
        </tr>
    </tbody>
</table>
</font><br />
</p>
<p><font size="3"><font style="background-color: #66ccff">
<table style="width: 100%" cellspacing="1" cellpadding="1" border="1">
    <tbody>
        <tr>
            <td>int a; <br />
            char c;<br />
            struct per_rec person;</td>
        </tr>
    </tbody>
</table>
</font></font></p>
<p><font size="3">A construct which specifies the name,parameters and return type of a function. For example a function definition would be: <br />
</font></p>
<font size="3">
<p><font style="background-color: #66ccff">
<table style="width: 100%" cellspacing="1" cellpadding="1" border="1">
    <tbody>
        <tr>
            <td><font style="background-color: #66ccff">long sqr(int num) <br />
            { <br />
            &nbsp;&nbsp;&nbsp;&nbsp; return(num*num);<br />
            } </font><br />
            </td>
        </tr>
    </tbody>
</table>
</font><br />
</p>
<p><font style="background-color: #3399ff" size="3"></font><font size="3">前者是"定义性声明(defining declaration)"或称为"定义(definition)",而后者是"引用性声明(referncing declaration)" 。从广义的角度来讲 声明中包含着定义，不过并非所有的声明都是定义，例如：int a 他既是声明，同时又是定义。然而对于 extern a 来讲他只是声明不是定义。他能在同一源程式或不同的源程式中重复声明。一般的情况下我们常常这样叙述，把建立空间的声明称之为"定义"，而把不必建立存储空间称之为"声明"。非常明显我们在这里指的声明是范围比较窄的，也就是说非定义性质的声明。 <br />
例如：在主函数中<br />
&nbsp;<font style="background-color: #66ccff">
<table style="width: 100%" cellspacing="1" cellpadding="1" border="1">
    <tbody>
        <tr>
            <td>
            <p>int main() <br />
            {&nbsp;<br />
            &nbsp;&nbsp;&nbsp; int a;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //这里是定义（分配空间的声明），他不能重复出现 <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //这里若写extern int a;或 int a;在VC6.0中编译均报错重复定义 </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;//(redefinition）<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;//这里写int a;在DEV-C++中编译报错重复声明(redeclaration) <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;//这里写extern int a;在DEV-C++中编译、运行均无问题 <br />
            &nbsp;&nbsp;&nbsp; extern int A;&nbsp; //这是个声明而不是定义，声明A是个已定义了的外部变量 <br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;//注意：声明外部变量时能把变量类型去掉如：extern A; <br />
            &nbsp;&nbsp;&nbsp; dosth();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //执行函数 <br />
            }&nbsp;<br />
            int A;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; //是定义，定义了A为整型的外部变量 <br />
            </p>
            </td>
        </tr>
    </tbody>
</table>
</font></font></p>
<p><font size="3">看来定义还是声明有时和编译器的处理也有关系。</font></p>
<p><font size="3">外部变量的"定义"和外部变量的"声明"是不相同的,外部变量的定义只能有一次，他的位置是在所有函数之外，而同一个文件中的外部变量声明能是多次的，他能在函数之内(哪个函数要用就在那个函数中声明)也能在函数之外(在外部变量的定义点之前)。系统会根据外部变量的定义(而不是根据外部变量的声明)分配存储空间的。对于外部变量来讲，初始化只能是在"定义"中进行,而不是在"声明"中 。<br />
所谓的"声明"，其作用，是声明该变量是个已在后面定义过的外部变量，仅仅是在为了"提前"引用该变量而作的"声明"而已。 extern 只作声明，不作所有定义 。</font></p>
<p><font size="3">用static来声明一个变量的作用有二：<br />
(1)&nbsp;对于局部变量用static声明，则是为该变量分配的空间在整个程式的执行期内都始终存在。 <br />
(2)&nbsp;外部变量用static来声明，则该变量的作用只限于本文件模块。</font></p>
<p><font size="3">进一步内容可查看： </font><font size="3">http://www-ccs.ucsd.edu/c/declare.html</font><font size="3"> </font></p>
</font>
<img src ="http://www.blogjava.net/tinysun/aggbug/322620.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-06-03 14:11 <a href="http://www.blogjava.net/tinysun/archive/2010/06/03/322620.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一道笔试题。。。</title><link>http://www.blogjava.net/tinysun/archive/2010/06/01/322479.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Tue, 01 Jun 2010 12:07:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/06/01/322479.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/322479.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/06/01/322479.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/322479.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/322479.html</trackback:ping><description><![CDATA[题目大意：<br />
如果整数大于0则输出1；<br />
等于0则输出0；<br />
小于0则输出1；<br />
要求不能用任何形式的判断语句。<br />
<br />
思路：<br />
设整数N，符号位可以通过如下宏得到：<br />
<font style="background-color: #cde9d1">#define SIGN(N) (N&gt;&gt;(sizeof(N)*8-1)&amp;0x01)</font><br />
那么如果N&gt;0，符号位为0；<br />
如果N=0，符号位为0；<br />
N&lt;0,符号位为1；<br />
这样没有办法区分正数和0！<br />
<br />
如果N&gt;0,N和N-1的符号位之和为0；<br />
N=0，N和N-1的符号位之和为1<br />
N&lt;0,N和N-1的符号位之和为2<br />
这样可以通过查表得到输出了。<br />
<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #008080">&nbsp;1</span><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">stdio.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">&nbsp;2</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
</span><span style="color: #008080">&nbsp;3</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #008000">//</span><span style="color: #008000">取得符号位</span><span style="color: #008000"><br />
</span><span style="color: #008080">&nbsp;4</span><span style="color: #008000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;SIGN(N)&nbsp;(N&gt;&gt;(sizeof(N)*8-1)&amp;0x01)</span><span style="color: #000000"><br />
</span><span style="color: #008080">&nbsp;5</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
</span><span style="color: #008080">&nbsp;6</span><span style="color: #000000"><img id="Codehighlighter1_79_86_Open_Image" onclick="this.style.display='none'; Codehighlighter1_79_86_Open_Text.style.display='none'; Codehighlighter1_79_86_Closed_Image.style.display='inline'; Codehighlighter1_79_86_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_79_86_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_79_86_Closed_Text.style.display='none'; Codehighlighter1_79_86_Open_Image.style.display='inline'; Codehighlighter1_79_86_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;T[]</span><span style="color: #000000">=</span><span id="Codehighlighter1_79_86_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_79_86_Open_Text"><span style="color: #000000">{</span><span style="color: #000000">1</span><span style="color: #000000">,</span><span style="color: #000000">0</span><span style="color: #000000">,</span><span style="color: #000000">-</span><span style="color: #000000">1</span><span style="color: #000000">}</span></span><span style="color: #000000">;<br />
</span><span style="color: #008080">&nbsp;7</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
</span><span style="color: #008080">&nbsp;8</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;sign(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;x)<br />
</span><span style="color: #008080">&nbsp;9</span><span style="color: #000000"><img id="Codehighlighter1_106_178_Open_Image" onclick="this.style.display='none'; Codehighlighter1_106_178_Open_Text.style.display='none'; Codehighlighter1_106_178_Closed_Image.style.display='inline'; Codehighlighter1_106_178_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_106_178_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_106_178_Closed_Text.style.display='none'; Codehighlighter1_106_178_Open_Image.style.display='inline'; Codehighlighter1_106_178_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span id="Codehighlighter1_106_178_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_106_178_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">10</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;index1</span><span style="color: #000000">=</span><span style="color: #000000">SIGN(x);<br />
</span><span style="color: #008080">11</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;index2</span><span style="color: #000000">=</span><span style="color: #000000">SIGN(x</span><span style="color: #000000">-</span><span style="color: #000000">1</span><span style="color: #000000">);<br />
</span><span style="color: #008080">12</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;T[index1</span><span style="color: #000000">+</span><span style="color: #000000">index2];<br />
</span><span style="color: #008080">13</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">14</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;main()<br />
</span><span style="color: #008080">15</span><span style="color: #000000"><img id="Codehighlighter1_191_243_Open_Image" onclick="this.style.display='none'; Codehighlighter1_191_243_Open_Text.style.display='none'; Codehighlighter1_191_243_Closed_Image.style.display='inline'; Codehighlighter1_191_243_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_191_243_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_191_243_Closed_Text.style.display='none'; Codehighlighter1_191_243_Open_Image.style.display='inline'; Codehighlighter1_191_243_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span id="Codehighlighter1_191_243_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_191_243_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">16</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&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">0</span><span style="color: #000000">;<br />
</span><span style="color: #008080">17</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
</span><span style="color: #008080">18</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000">"</span><span style="color: #000000">%d\n</span><span style="color: #000000">"</span><span style="color: #000000">,sign(x));<br />
</span><span style="color: #008080">19</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
</span><span style="color: #008080">20</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br />
</span><span style="color: #008080">21</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span></div>
<br />
<img src ="http://www.blogjava.net/tinysun/aggbug/322479.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-06-01 20:07 <a href="http://www.blogjava.net/tinysun/archive/2010/06/01/322479.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>讲讲volatile的作用</title><link>http://www.blogjava.net/tinysun/archive/2010/05/30/322277.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sun, 30 May 2010 06:48:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/05/30/322277.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/322277.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/05/30/322277.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/322277.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/322277.html</trackback:ping><description><![CDATA[<div>一个定义为volatile的变量是说这变量可能会被意想不到地改变，这样，编译器就不会去假设这个变量的值了。精确地说就是，优化器在用到这个变量时必须每次都小心地重新读取这个变量的值，而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子： <br />
&nbsp;&nbsp;&nbsp;&nbsp;1).&nbsp;并行设备的硬件寄存器（如：状态寄存器） <br />
&nbsp;&nbsp;&nbsp;&nbsp;2).&nbsp;一个中断服务子程序中会访问到的非自动变量(Non-automatic&nbsp;variables) <br />
&nbsp;&nbsp;&nbsp;&nbsp;3).&nbsp;多线程应用中被几个任务共享的变量 <br />
&nbsp;&nbsp;&nbsp;&nbsp;回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道，所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;假设被面试者正确地回答了这是问题（嗯，怀疑这否会是这样），我将稍微深究一下，看一下这家伙是不是直正懂得volatile完全的重要性。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;1).&nbsp;一个参数既可以是const还可以是volatile吗？解释为什么。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;2).&nbsp;一个指针可以是volatile&nbsp;吗？解释为什么。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;3).&nbsp;下面的函数有什么错误： <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;square(volatile&nbsp;int&nbsp;*ptr) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;*ptr&nbsp;*&nbsp;*ptr; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;下面是答案： <br />
&nbsp;&nbsp;&nbsp;&nbsp;1).&nbsp;是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;2).&nbsp;是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;3).&nbsp;这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方，但是，由于*ptr指向一个volatile型参数，编译器将产生类似下面的代码： <br />
&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;square(volatile&nbsp;int&nbsp;*ptr)&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;a,b; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;=&nbsp;*ptr; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;=&nbsp;*ptr; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;a&nbsp;*&nbsp;b; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
&nbsp;&nbsp;&nbsp;&nbsp;由于*ptr的值可能被意想不到地该变，因此a和b可能是不同的。结果，这段代码可能返不是你所期望的平方值！正确的代码如下： <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;square(volatile&nbsp;int&nbsp;*ptr)&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;a; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;=&nbsp;*ptr; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;a&nbsp;*&nbsp;a; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br />
</div>
<div>讲讲我的理解：&nbsp;（欢迎打板子...~~！） <br />
<br />
关键在于两个地方：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp; <br />
1.&nbsp;编译器的优化&nbsp;&nbsp;(请高手帮我看看下面的理解) <br />
<br />
在本次线程内,&nbsp;当读取一个变量时，为提高存取速度，编译器优化时有时会先把变量读取到一个寄存器中；以后，再取变量值时，就直接从寄存器中取值； <br />
<br />
当变量值在本线程里改变时，会同时把变量的新值copy到该寄存器中，以便保持一致 <br />
<br />
当变量在因别的线程等而改变了值，该寄存器的值不会相应改变，从而造成应用程序读取的值和实际的变量值不一致 <br />
<br />
当该寄存器在因别的线程等而改变了值，原变量的值不会改变，从而造成应用程序读取的值和实际的变量值不一致&nbsp; <br />
<br />
<br />
举一个不太准确的例子：&nbsp; <br />
<br />
发薪资时，会计每次都把员工叫来登记他们的银行卡号；一次会计为了省事，没有即时登记，用了以前登记的银行卡号；刚好一个员工的银行卡丢了，已挂失该银行卡号；从而造成该员工领不到工资&nbsp; <br />
<br />
员工&nbsp;－－&nbsp;原始变量地址&nbsp; <br />
银行卡号&nbsp;－－&nbsp;原始变量在寄存器的备份&nbsp; <br />
<br />
<br />
2.&nbsp;在什么情况下会出现(如1楼所说) <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;1).&nbsp;并行设备的硬件寄存器（如：状态寄存器）&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;2).&nbsp;一个中断服务子程序中会访问到的非自动变量(Non-automatic&nbsp;variables)&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;3).&nbsp;多线程应用中被几个任务共享的变量&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
补充：&nbsp;volatile应该解释为&#8220;直接存取原始内存地址&#8221;比较合适，&#8220;易变的&#8221;这种解释简直有点误导人；&nbsp; <br />
<br />
&#8220;易变&#8221;是因为外在因素引起的，象多线程，中断等，并不是因为用volatile修饰了的变量就是&#8220;易变&#8221;了，假如没有外因，即使用volatile定义，它也不会变化； <br />
<br />
而用volatile定义之后，其实这个变量就不会因外因而变化了，可以放心使用了；&nbsp;大家看看前面那种解释（易变的）是不是在误导人 <br />
<br />
<br />
－－－－－－－－－－－－简明示例如下：－－－－－－－－－－－－－－－－－－ <br />
<br />
volatile关键字是一种类型修饰符，用它声明的类型变量表示可以被某些编译器未知的因素更改，比如：操作系统、硬件或者其它线程等。遇到这个关键字声明的变量，编译器对访问该变量的代码就不再进行优化，从而可以提供对特殊地址的稳定访问。 <br />
使用该关键字的例子如下： <br />
int&nbsp;volatile&nbsp;nVint; <br />
&gt;&gt;&gt;&gt;当要求使用volatile&nbsp;声明的变量的值的时候，系统总是重新从它所在的内存读取数据，即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。 <br />
例如： <br />
volatile&nbsp;int&nbsp;i=10; <br />
int&nbsp;a&nbsp;=&nbsp;i; <br />
... <br />
//其他代码，并未明确告诉编译器，对i进行过操作 <br />
int&nbsp;b&nbsp;=&nbsp;i; <br />
&gt;&gt;&gt;&gt;volatile&nbsp;指出&nbsp;i是随时可能发生变化的，每次使用它的时候必须从i的地址中读取，因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是，由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作，它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来，如果i是一个寄存器变量或者表示一个端口数据就容易出错，所以说volatile可以保证对特殊地址的稳定访问。 <br />
&gt;&gt;&gt;&gt;注意，在vc6中，一般调试模式没有进行代码优化，所以这个关键字的作用看不出来。下面通过插入汇编代码，测试有无volatile关键字，对程序最终代码的影响： <br />
&gt;&gt;&gt;&gt;首先，用classwizard建一个win32&nbsp;console工程，插入一个voltest.cpp文件，输入下面的代码： <br />
&gt;&gt; <br />
＃i nclude&nbsp;&lt;stdio.h&gt; <br />
void&nbsp;main() <br />
{ <br />
int&nbsp;i=10; <br />
int&nbsp;a&nbsp;=&nbsp;i; <br />
printf("i=&nbsp;%d",a); <br />
//下面汇编语句的作用就是改变内存中i的值，但是又不让编译器知道 <br />
__asm&nbsp;{ <br />
mov&nbsp;dword&nbsp;ptr&nbsp;[ebp-4],&nbsp;20h <br />
} <br />
int&nbsp;b&nbsp;=&nbsp;i; <br />
printf("i=&nbsp;%d",b); <br />
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
然后，在调试版本模式运行程序，输出结果如下： <br />
i&nbsp;=&nbsp;10 <br />
i&nbsp;=&nbsp;32 <br />
然后，在release版本模式运行程序，输出结果如下： <br />
i&nbsp;=&nbsp;10 <br />
i&nbsp;=&nbsp;10 <br />
输出的结果明显表明，release模式下，编译器对代码进行了优化，第二次没有输出正确的i值。下面，我们把&nbsp;i的声明加上volatile关键字，看看有什么变化： <br />
＃i nclude&nbsp;&lt;stdio.h&gt; <br />
void&nbsp;main() <br />
{ <br />
volatile&nbsp;int&nbsp;i=10; <br />
int&nbsp;a&nbsp;=&nbsp;i; <br />
printf("i=&nbsp;%d",a); <br />
__asm&nbsp;{ <br />
mov&nbsp;dword&nbsp;ptr&nbsp;[ebp-4],&nbsp;20h <br />
} <br />
int&nbsp;b&nbsp;=&nbsp;i; <br />
printf("i=&nbsp;%d",b); <br />
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
分别在调试版本和release版本运行程序，输出都是： <br />
i&nbsp;=&nbsp;10 <br />
i&nbsp;=&nbsp;32 <br />
这说明这个关键字发挥了它的作用！ <br />
<br />
－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－ <br />
<br />
<br />
volatile对应的变量可能在你的程序本身不知道的情况下发生改变 <br />
比如多线程的程序，共同访问的内存当中，多个程序都可以操纵这个变量 <br />
你自己的程序，是无法判定合适这个变量会发生变化 <br />
还比如，他和一个外部设备的某个状态对应，当外部设备发生操作的时候，通过驱动程序和中断事件，系统改变了这个变量的数值，而你的程序并不知道。 <br />
对于volatile类型的变量，系统每次用到他的时候都是直接从对应的内存当中提取，而不会利用cache当中的原有数值，以适应它的未知何时会发生的变化，系统对这种变量的处理不会做优化——显然也是因为它的数值随时都可能变化的情况。 <br />
<br />
-------------------------------------------------------------------------------- <br />
<br />
典型的例子 <br />
for&nbsp;(&nbsp;int&nbsp;i=0;&nbsp;i&lt;100000;&nbsp;i++); <br />
这个语句用来测试空循环的速度的 <br />
但是编译器肯定要把它优化掉，根本就不执行 <br />
如果你写成&nbsp; <br />
for&nbsp;(&nbsp;volatile&nbsp;int&nbsp;i=0;&nbsp;i&lt;100000;&nbsp;i++); <br />
它就会执行了 <br />
<br />
volatile的本意是&#8220;易变的&#8221;&nbsp; <br />
由于访问寄存器的速度要快过RAM，所以编译器一般都会作减少存取外部RAM的优化。比如： <br />
<br />
static&nbsp;int&nbsp;i=0; <br />
<br />
int&nbsp;main(void) <br />
{ <br />
... <br />
while&nbsp;(1) <br />
{ <br />
if&nbsp;(i)&nbsp;dosomething(); <br />
} <br />
} <br />
<br />
/*&nbsp;Interrupt&nbsp;service&nbsp;routine.&nbsp;*/ <br />
void&nbsp;ISR_2(void) <br />
{ <br />
i=1; <br />
} <br />
<br />
程序的本意是希望ISR_2中断产生时，在main当中调用dosomething函数，但是，由于编译器判断在main函数里面没有修改过i，因此 <br />
可能只执行一次对从i到某寄存器的读操作，然后每次if判断都只使用这个寄存器里面的&#8220;i副本&#8221;，导致dosomething永远也不会被 <br />
调用。如果将将变量加上volatile修饰，则编译器保证对此变量的读写操作都不会被优化（肯定执行）。此例中i也应该如此说明。 <br />
<br />
一般说来，volatile用在如下的几个地方： <br />
<br />
1、中断服务程序中修改的供其它程序检测的变量需要加volatile； <br />
<br />
2、多任务环境下各任务间共享的标志应该加volatile； <br />
<br />
3、存储器映射的硬件寄存器通常也要加volatile说明，因为每次对它的读写都可能由不同意义； <br />
<br />
另外，以上这几种情况经常还要同时考虑数据的完整性（相互关联的几个标志读了一半被打断了重写），在1中可以通过关中断来实 <br />
现，2中可以禁止任务调度，3中则只能依靠硬件的良好设计了。&nbsp;<br />
&nbsp; <br />
</div>
<img src ="http://www.blogjava.net/tinysun/aggbug/322277.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-05-30 14:48 <a href="http://www.blogjava.net/tinysun/archive/2010/05/30/322277.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于C++调用默认构造函数构造对象的困惑</title><link>http://www.blogjava.net/tinysun/archive/2010/05/19/321411.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Wed, 19 May 2010 12:41:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/05/19/321411.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/321411.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/05/19/321411.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/321411.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/321411.html</trackback:ping><description><![CDATA[<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #008080">&nbsp;1</span><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Test<br />
</span><span style="color: #008080">&nbsp;2</span><span style="color: #000000"><img id="Codehighlighter1_11_79_Open_Image" onclick="this.style.display='none'; Codehighlighter1_11_79_Open_Text.style.display='none'; Codehighlighter1_11_79_Closed_Image.style.display='inline'; Codehighlighter1_11_79_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_11_79_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_11_79_Closed_Text.style.display='none'; Codehighlighter1_11_79_Open_Image.style.display='inline'; Codehighlighter1_11_79_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span id="Codehighlighter1_11_79_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_11_79_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">&nbsp;3</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;:<br />
</span><span style="color: #008080">&nbsp;4</span><span style="color: #000000"><img id="Codehighlighter1_35_36_Open_Image" onclick="this.style.display='none'; Codehighlighter1_35_36_Open_Text.style.display='none'; Codehighlighter1_35_36_Closed_Image.style.display='inline'; Codehighlighter1_35_36_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_35_36_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_35_36_Closed_Text.style.display='none'; Codehighlighter1_35_36_Open_Image.style.display='inline'; Codehighlighter1_35_36_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;Test(&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;)&nbsp;</span><span id="Codehighlighter1_35_36_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_35_36_Open_Text"><span style="color: #000000">{}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">&nbsp;5</span><span style="color: #000000"><img id="Codehighlighter1_49_50_Open_Image" onclick="this.style.display='none'; Codehighlighter1_49_50_Open_Text.style.display='none'; Codehighlighter1_49_50_Closed_Image.style.display='inline'; Codehighlighter1_49_50_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_49_50_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_49_50_Closed_Text.style.display='none'; Codehighlighter1_49_50_Open_Image.style.display='inline'; Codehighlighter1_49_50_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;Test()&nbsp;</span><span id="Codehighlighter1_49_50_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_49_50_Open_Text"><span style="color: #000000">{}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">&nbsp;6</span><span style="color: #000000"><img id="Codehighlighter1_67_68_Open_Image" onclick="this.style.display='none'; Codehighlighter1_67_68_Open_Text.style.display='none'; Codehighlighter1_67_68_Closed_Image.style.display='inline'; Codehighlighter1_67_68_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_67_68_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_67_68_Closed_Text.style.display='none'; Codehighlighter1_67_68_Open_Image.style.display='inline'; Codehighlighter1_67_68_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;fun()&nbsp;</span><span id="Codehighlighter1_67_68_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_67_68_Open_Text"><span style="color: #000000">{}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">&nbsp;7</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
</span><span style="color: #008080">&nbsp;8</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i;<br />
</span><span style="color: #008080">&nbsp;9</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000">;<br />
</span><span style="color: #008080">10</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;main(&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;)<br />
</span><span style="color: #008080">11</span><span style="color: #000000"><img id="Codehighlighter1_100_152_Open_Image" onclick="this.style.display='none'; Codehighlighter1_100_152_Open_Text.style.display='none'; Codehighlighter1_100_152_Closed_Image.style.display='inline'; Codehighlighter1_100_152_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_100_152_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_100_152_Closed_Text.style.display='none'; Codehighlighter1_100_152_Open_Image.style.display='inline'; Codehighlighter1_100_152_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span id="Codehighlighter1_100_152_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_100_152_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">12</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;Test&nbsp;a(</span><span style="color: #000000">1</span><span style="color: #000000">);<br />
</span><span style="color: #008080">13</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;Test&nbsp;b();<br />
</span><span style="color: #008080">14</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
</span><span style="color: #008080">15</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;a.fun();<br />
</span><span style="color: #008080">16</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;b.fun();<br />
</span><span style="color: #008080">17</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">18</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span></div>
编译信息：<br />
<p><font style="background-color: #cde9d1">--------------------Configuration: hex - Win32 Debug--------------------<br />
Compiling...<br />
hex.cpp<br />
E:\Projects\C++\Hex\hex.cpp(42) : error C2228: left of '.fun' must have class/struct/union type<br />
Error executing cl.exe.</font></p>
<p><font style="background-color: #cde9d1">hex.exe - 1 error(s), 0 warning(s)<br />
</font></p>
结论：<br />
也就是说Microsoft C++编译器把Test b();作为一个函数声明对待了。<br />
调用默认的无参数的构造函数来构造对象应该这样定义：Test b;
<img src ="http://www.blogjava.net/tinysun/aggbug/321411.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-05-19 20:41 <a href="http://www.blogjava.net/tinysun/archive/2010/05/19/321411.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>条款7:为内存不足的情况预做准备.</title><link>http://www.blogjava.net/tinysun/archive/2010/05/13/320798.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 13 May 2010 06:37:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/05/13/320798.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/320798.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/05/13/320798.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/320798.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/320798.html</trackback:ping><description><![CDATA[<p>1,当operator new无法满足内存需求时,抛出std::bad_alloc. <br />
下面是一个验证的代码: <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Cpp代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="#"><img alt="复制代码" src="http://www.blogjava.net/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-cpp">
    <li><span><span class="preprocessor">#include&nbsp;&lt;iostream&gt; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="preprocessor">#include&nbsp;&lt;stdexcept&gt; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">using</span><span>&nbsp;</span><span class="keyword">namespace</span><span>&nbsp;std&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="datatypes">int</span><span>&nbsp;main&nbsp;() &nbsp;&nbsp;</span></span></li>
    <li><span>{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="datatypes">int</span><span>*&nbsp;p=NULL; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>(1) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p=</span><span class="keyword">new</span><span>&nbsp;</span><span class="datatypes">int</span><span>[10000]; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span><span class="keyword">catch</span><span>(std::bad_alloc&amp;) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;</span><span class="string">"no&nbsp;enough&nbsp;mem."</span><span>&lt;&lt;endl; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;0&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none" class="cpp" name="code">#include &lt;iostream&gt;
#include &lt;stdexcept&gt;
using namespace std ;
int main ()
{
try
{
int* p=NULL;
while(1)
p=new int[10000];
}catch(std::bad_alloc&amp;)
{
cout&lt;&lt;"no enough mem."&lt;&lt;endl;
}
return 0 ;
}
</pre>
<p><br />
<br />
2,C++的一个公约: <br />
当operator new无法满足需求时,它会在抛出exception前先调用一个专属的错误处理函数. <br />
我们称之为:new-handler. <br />
<br />
3,当operator无法满足内存需求时,它会不只一次的调用new-handler函数; <br />
它会不断的重复调用,直到找到足够的内存. <br />
一个设计良好的new-handler函数必须完成下面几件事: <br />
(1)让更多内存可用. <br />
例如:事先在程序起始处配置一大块内存,然后在new-handler第一次被调用时释放之. <br />
(2)配置另外一个new-handler,其手上握有比较多的资源. <br />
(3)卸除new-handler,set_new_handler(NULL) <br />
将不再调用专属函数,而直接抛出exception. <br />
(4)抛出exception. <br />
(5)不回返,直接调用abort()或exit. <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Cpp代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="#"><img alt="复制代码" src="http://www.blogjava.net/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-cpp">
    <li><span><span class="preprocessor">#include&nbsp;&lt;iostream&gt; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="preprocessor">#include&nbsp;&lt;stdexcept&gt; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">using</span><span>&nbsp;</span><span class="keyword">namespace</span><span>&nbsp;std&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">void</span><span>&nbsp;noMoreMemory() &nbsp;&nbsp;</span></span></li>
    <li><span>{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;</span><span class="string">"Unable&nbsp;to&nbsp;satify&nbsp;request&nbsp;for&nbsp;memory."</span><span>&lt;&lt;endl; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//原则(5):不回返 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;abort();</span><span class="comment">//不加,将会是一个死循环. </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//原则(4):也可以通过抛出一个异常 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//throw&nbsp;std::bad_alloc(); </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="datatypes">int</span><span>&nbsp;main&nbsp;() &nbsp;&nbsp;</span></span></li>
    <li><span>{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//typedef&nbsp;void&nbsp;(*new_handler)();&nbsp;&nbsp;头文件中已经给出 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//设定自己的专属错误处理函数. </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//返回之前的new_handler </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;new_handler&nbsp;old_new_handler=set_new_handler(noMoreMemory); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//set_new_handler(NULL);&nbsp;//卸除new-handler,抛出异常. </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="datatypes">int</span><span>*&nbsp;p=NULL; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>(1) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p=</span><span class="keyword">new</span><span>&nbsp;</span><span class="datatypes">int</span><span>[10000]; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span><span class="keyword">catch</span><span>(std::bad_alloc&amp;) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;</span><span class="string">"no&nbsp;more&nbsp;memory."</span><span>&lt;&lt;endl; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_new_handler(old_new_handler); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;set_new_handler(old_new_handler); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;0&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none" class="cpp" name="code">#include &lt;iostream&gt;
#include &lt;stdexcept&gt;
using namespace std ;
void noMoreMemory()
{
cout&lt;&lt;"Unable to satify request for memory."&lt;&lt;endl;
//原则(5):不回返
abort();//不加,将会是一个死循环.
//原则(4):也可以通过抛出一个异常
//throw std::bad_alloc();
}
int main ()
{
//typedef void (*new_handler)();  头文件中已经给出
//设定自己的专属错误处理函数.
//返回之前的new_handler
new_handler old_new_handler=set_new_handler(noMoreMemory);
//set_new_handler(NULL); //卸除new-handler,抛出异常.
try
{
int* p=NULL;
while(1)
p=new int[10000];
}catch(std::bad_alloc&amp;)
{
cout&lt;&lt;"no more memory."&lt;&lt;endl;
set_new_handler(old_new_handler);
}
set_new_handler(old_new_handler);
return 0 ;
}
</pre>
<p><br />
4,设定类class专属的new-handler. <br />
一个强大的类模板. <br />
</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Cpp代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="#"><img alt="复制代码" src="http://www.blogjava.net/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-cpp">
    <li><span><span class="preprocessor">#include&nbsp;&lt;iostream&gt; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="preprocessor">#include&nbsp;&lt;stdexcept&gt; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">using</span><span>&nbsp;</span><span class="keyword">namespace</span><span>&nbsp;std&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">template</span><span>&lt;</span><span class="keyword">class</span><span>&nbsp;T&gt; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">class</span><span>&nbsp;NewHandlerSupport &nbsp;&nbsp;</span></span></li>
    <li><span>{ &nbsp;&nbsp;</span></li>
    <li><span class="keyword">public</span><span>: &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">static</span><span>&nbsp;new_handler&nbsp;set_new_handler(new_handler&nbsp;p); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>*&nbsp;operator&nbsp;</span><span class="keyword">new</span><span>(</span><span class="datatypes">size_t</span><span>&nbsp;size); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>*&nbsp;operator&nbsp;</span><span class="keyword">new</span><span>[](</span><span class="datatypes">size_t</span><span>&nbsp;size); &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">private</span><span>: &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">static</span><span>&nbsp;new_handler&nbsp;currentHandler; &nbsp;&nbsp;</span></span></li>
    <li><span>}; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">template</span><span>&lt;</span><span class="keyword">class</span><span>&nbsp;T&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>new_handler&nbsp;NewHandlerSupport&lt;T&gt;::set_new_handler(new_handler&nbsp;p) &nbsp;&nbsp;</span></li>
    <li><span>{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;new_handler&nbsp;oldHandler=currentHandler; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;currentHandler=p; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;oldHandler;&nbsp;</span><span class="comment">//返回之前的专属函数 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">template</span><span>&lt;</span><span class="keyword">class</span><span>&nbsp;T&gt; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">void</span><span>*&nbsp;NewHandlerSupport&lt;T&gt;::operator&nbsp;</span><span class="keyword">new</span><span>(</span><span class="datatypes">size_t</span><span>&nbsp;size) &nbsp;&nbsp;</span></span></li>
    <li><span>{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//下面调用标准的set_new_handler </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;new_handler&nbsp;globalHandler=std::set_new_handler(currentHandler); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">void</span><span>*&nbsp;memory; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//使用标准的new. </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memory=::operator&nbsp;</span><span class="keyword">new</span><span>(size); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span><span class="keyword">catch</span><span>(std::bad_alloc) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::set_new_handler(globalHandler); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>;&nbsp;</span><span class="comment">//继续抛出异常 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;std::set_new_handler(globalHandler);&nbsp;</span><span class="comment">//返回原来的设置 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;memory;&nbsp;</span><span class="comment">//返回之前的专属函数 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">template</span><span>&lt;</span><span class="keyword">class</span><span>&nbsp;T&gt; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>*&nbsp;NewHandlerSupport&lt;T&gt;::operator&nbsp;</span><span class="keyword">new</span><span>[](</span><span class="datatypes">size_t</span><span>&nbsp;size) &nbsp;&nbsp;</span></span></li>
    <li><span>{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;operator&nbsp;</span><span class="keyword">new</span><span>(size); &nbsp;&nbsp;</span></span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">template</span><span>&lt;</span><span class="keyword">class</span><span>&nbsp;T&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>new_handler&nbsp;NewHandlerSupport&lt;T&gt;::currentHandler;&nbsp;</span><span class="comment">//设置为0 </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">void</span><span>&nbsp;noMoreMemory() &nbsp;&nbsp;</span></span></li>
    <li><span>{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;</span><span class="string">"Unable&nbsp;to&nbsp;satify&nbsp;request&nbsp;for&nbsp;memory."</span><span>&lt;&lt;endl; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//abort(); </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;std::bad_alloc(); &nbsp;&nbsp;</span></span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">class</span><span>&nbsp;X&nbsp;:&nbsp;</span><span class="keyword">public</span><span>&nbsp;NewHandlerSupport&lt;X&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>{ &nbsp;&nbsp;</span></li>
    <li><span>}; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="datatypes">int</span><span>&nbsp;main&nbsp;() &nbsp;&nbsp;</span></span></li>
    <li><span>{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;X::set_new_handler(noMoreMemory); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X*&nbsp;p=NULL; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//先调用专属函数,然后有专属函数抛出异常. </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>(1) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p=</span><span class="keyword">new</span><span>&nbsp;X[100000]; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span><span class="keyword">catch</span><span>(std::bad_alloc&amp;) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;</span><span class="string">"no&nbsp;more&nbsp;memory."</span><span>&lt;&lt;endl; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;X::set_new_handler(0); &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X*&nbsp;p=NULL; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//不再调用专属函数,直接捕获异常. </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>(1) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p=</span><span class="keyword">new</span><span>&nbsp;X[100000]; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}</span><span class="keyword">catch</span><span>(std::bad_alloc&amp;) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;</span><span class="string">"no&nbsp;more&nbsp;memory."</span><span>&lt;&lt;endl; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;0&nbsp;; &nbsp;&nbsp;</span></span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none" class="cpp" name="code">#include &lt;iostream&gt;
#include &lt;stdexcept&gt;
using namespace std ;
template&lt;class T&gt;
class NewHandlerSupport
{
public:
static new_handler set_new_handler(new_handler p);
static void* operator new(size_t size);
static void* operator new[](size_t size);
private:
static new_handler currentHandler;
};
template&lt;class T&gt;
new_handler NewHandlerSupport&lt;T&gt;::set_new_handler(new_handler p)
{
new_handler oldHandler=currentHandler;
currentHandler=p;
return oldHandler; //返回之前的专属函数
}
template&lt;class T&gt;
void* NewHandlerSupport&lt;T&gt;::operator new(size_t size)
{
//下面调用标准的set_new_handler
new_handler globalHandler=std::set_new_handler(currentHandler);
void* memory;
try
{
//使用标准的new.
memory=::operator new(size);
}catch(std::bad_alloc)
{
std::set_new_handler(globalHandler);
throw; //继续抛出异常
}
std::set_new_handler(globalHandler); //返回原来的设置
return memory; //返回之前的专属函数
}
template&lt;class T&gt;
static void* NewHandlerSupport&lt;T&gt;::operator new[](size_t size)
{
return operator new(size);
}
template&lt;class T&gt;
new_handler NewHandlerSupport&lt;T&gt;::currentHandler; //设置为0
void noMoreMemory()
{
cout&lt;&lt;"Unable to satify request for memory."&lt;&lt;endl;
//abort();
throw std::bad_alloc();
}
class X : public NewHandlerSupport&lt;X&gt;
{
};
int main ()
{
X::set_new_handler(noMoreMemory);
try
{
X* p=NULL;
//先调用专属函数,然后有专属函数抛出异常.
while(1)
p=new X[100000];
}catch(std::bad_alloc&amp;)
{
cout&lt;&lt;"no more memory."&lt;&lt;endl;
}
X::set_new_handler(0);
try
{
X* p=NULL;
//不再调用专属函数,直接捕获异常.
while(1)
p=new X[100000];
}catch(std::bad_alloc&amp;)
{
cout&lt;&lt;"no more memory."&lt;&lt;endl;
}
return 0 ;
}
</pre>
<p><br />
5,旧的编译器: <br />
如果内存配置失败不会抛出异常,只是返回0. <br />
测试实例: <br />
int* p=new (nothrow)int; <br />
if(p==0) <br />
cout&lt;&lt;"memory error;"&lt;&lt;endl; <br />
</p>
<img src ="http://www.blogjava.net/tinysun/aggbug/320798.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-05-13 14:37 <a href="http://www.blogjava.net/tinysun/archive/2010/05/13/320798.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于宏定义,常见宏及其对应的头文件</title><link>http://www.blogjava.net/tinysun/archive/2010/05/13/320796.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 13 May 2010 06:11:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/05/13/320796.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/320796.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/05/13/320796.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/320796.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/320796.html</trackback:ping><description><![CDATA[(1)#ifndef和 #define组合 <br />
一般用于头文件中,防止该头文件被重复引用. <br />
其用法一般为： <br />
#ifndef &lt;标识&gt; <br />
&nbsp; #define &lt;标识&gt; <br />
&nbsp; .........&nbsp;&nbsp; // include or define sth. <br />
#else <br />
&nbsp; ...... <br />
#endif <br />
&lt;标识&gt;在理论上来说可以是自由命名的，但每个头文件的这个&#8220;标识&#8221;都应该是唯一的。 <br />
标识的命名规则一般是头文件名全大写，前后加下划线，并把文件名中的&#8220;.&#8221;也变成下划线，如：stdio.h对应的就是: <br />
#ifndef _STDIO_H_ <br />
#define _STDIO_H_ <br />
.........&nbsp;&nbsp; // include or define sth. <br />
#endif <br />
<br />
(2) <br />
#if 0 <br />
中间可以随见加入各种文字 <br />
#endif <br />
<br />
(3) <br />
__FILE__:文件名常量: <br />
__DATE__:日期常量 <br />
__TIME__:时间常量 <br />
__LINE__:所在行常量 <br />
EOF:错误常量 <br />
CLOCKS_PER_SEC:cpu在一秒内的计时单元数 <br />
&lt;cstdlib&gt; EXIT_SUCESS(总是定义W为0),XIT_FAILURE <br />
&lt;cstddef&gt; size_t <br />
&lt;cassert&gt; assert()宏 <br />
&lt;memory&gt; auto_ptr类模版 <br />
<br />
判断一段程序是由C 编译还是由C++编译: <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Cpp代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="#"><img alt="复制代码" src="http://www.blogjava.net/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-cpp">
    <li><span><span class="preprocessor">#ifdef&nbsp;__cplusplus </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;</span><span class="string">"c++"</span><span>&lt;&lt;endl; &nbsp;&nbsp;</span></span></li>
    <li><span class="preprocessor">#else </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;</span><span class="string">"c"</span><span>&lt;&lt;endl; &nbsp;&nbsp;</span></span></li>
    <li><span class="preprocessor">#endif</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre style="display: none" class="cpp" name="code">    #ifdef __cplusplus
cout&lt;&lt;"c++"&lt;&lt;endl;
#else
cout&lt;&lt;"c"&lt;&lt;endl;
#endif
</pre>
<br />
<img src ="http://www.blogjava.net/tinysun/aggbug/320796.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-05-13 14:11 <a href="http://www.blogjava.net/tinysun/archive/2010/05/13/320796.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C指针声明解读之左右法则</title><link>http://www.blogjava.net/tinysun/archive/2010/05/04/320072.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Tue, 04 May 2010 13:33:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/05/04/320072.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/320072.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/05/04/320072.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/320072.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/320072.html</trackback:ping><description><![CDATA[<p><font style="background-color: #cde9d1">C 语言所有复杂的指针声明，都是由各种声明嵌套构成的。如何解读复杂指针声明呢？右左法则是一个既著名又常用的方法。不过，右左法则其实并不是C 标准里面的内容，它是从C 标准的声明规定中归纳出来的方法。C 标准的声明规则，是用来解决如何创建声明的，而右左法则是用来解决如何辩识一个声明的，两者可以说是相反的。右左法则的英文原文是这样说的：<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The&nbsp;&nbsp; right-left&nbsp;&nbsp; rule:&nbsp;&nbsp; Start&nbsp;&nbsp; reading&nbsp;&nbsp; the&nbsp;&nbsp; declaration&nbsp;&nbsp; from&nbsp;&nbsp; the&nbsp;&nbsp; innermost&nbsp;&nbsp; parentheses,&nbsp;&nbsp; go&nbsp;&nbsp; right,&nbsp;&nbsp; and&nbsp;&nbsp; then&nbsp;&nbsp; go&nbsp;&nbsp; left.&nbsp;&nbsp; When&nbsp;&nbsp; you&nbsp;&nbsp; encounter&nbsp; parentheses,&nbsp;&nbsp; the&nbsp;&nbsp; direction&nbsp;&nbsp; should&nbsp;&nbsp; be&nbsp;&nbsp; reversed.&nbsp;&nbsp; Once&nbsp;&nbsp; everything&nbsp;&nbsp; in&nbsp;&nbsp; the&nbsp;&nbsp; parentheses&nbsp;&nbsp; has&nbsp;&nbsp; been&nbsp;&nbsp; parsed,&nbsp;&nbsp; jump&nbsp;&nbsp; out&nbsp; of&nbsp;&nbsp; it.&nbsp;&nbsp; Continue&nbsp;&nbsp; till&nbsp;&nbsp; the&nbsp;&nbsp; whole&nbsp;&nbsp; declaration&nbsp;&nbsp; has&nbsp; been&nbsp;&nbsp; parsed.&nbsp;&nbsp; <br />
&nbsp;<br />
&nbsp;<br />
这段英文的翻译如下：<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 右左法则：首先从最里面的圆括号看起，然后往右看，再往左看。每当遇到圆括号时，就应该掉转阅读方向。一旦解析完圆括号里面所有的东西，就跳出圆括号。重复这个过程直到整个声明解析完毕。<br />
&nbsp;<br />
笔者要对这个法则进行一个小小的修正，应该是从未定义的标识符开始阅读，而不是从括号读起，之所以是未定义的标识符，是因为一个声明里面可能有多个标识符，但未定义的标识符只会有一个。<br />
&nbsp;<br />
&nbsp; 现在通过一些例子来讨论右左法则的应用，先从最简单的开始，逐步加深：<br />
&nbsp;<br />
int&nbsp;&nbsp; (*func)(int&nbsp;&nbsp; *p); <br />
&nbsp;<br />
首先找到那个未定义的标识符，就是func ，它的外面有一对圆括号，而且左边是一个* 号，这说明func 是一个指针，然后跳出这个圆括号，先看右边，也是一个圆括号，这说明(*func) 是一个函数，而func 是一个指向这类函数的指针，就是一个函数指针，这类函数具有int* 类型的形参，返回值类型是int 。<br />
&nbsp;<br />
int&nbsp;&nbsp; (*func)(int&nbsp;&nbsp; *p,&nbsp;&nbsp; int&nbsp;&nbsp; (*f)(int*)); <br />
&nbsp;<br />
func 被一对括号包含，且左边有一个* 号，说明func 是一个指针，跳出括号，右边也有个括号，那么func 是一个指向函数的指针，这类函数具有int&nbsp;&nbsp; * 和int&nbsp;&nbsp; (*)(int*) 这样的形参，返回值为int 类型。再来看一看func 的形参int&nbsp;&nbsp; (*f)(int*) ，类似前面的解释，f 也是一个函数指针，指向的函数具有int* 类型的形参，返回值为int 。<br />
&nbsp;<br />
int&nbsp;&nbsp; (*func[5])(int&nbsp;&nbsp; *p); <br />
&nbsp;<br />
func 右边是一个[] 运算符，说明func 是一个具有5 个元素的数组，func 的左边有一个* ，说明func 的元素是指针，要注意这里的* 不是修饰func 的，而是修饰func[5] 的，原因是[] 运算符优先级比* 高，func 先跟[] 结合，因此* 修饰的是func[5] 。跳出这个括号，看右边，也是一对圆括号，说明func 数组的元素是函数类型的指针，它所指向的函数具有int* 类型的形参，返回值类型为int 。<br />
&nbsp; int&nbsp;&nbsp; (*(*func)[5])(int&nbsp;&nbsp; *p); <br />
&nbsp;<br />
func 被一个圆括号包含，左边又有一个* ，那么func 是一个指针，跳出括号，右边是一个[] 运算符号，说明func 是一个指向数组的指针，现在往左看，左边有一个* 号，说明这个数组的元素是指针，再跳出括号，右边又有一个括号，说明这个数组的元素是指向函数的指针。总结一下，就是：func 是一个指向数组的指针，这个数组的元素是函数指针，这些指针指向具有int* 形参，返回值为int 类型的函数。<br />
&nbsp;<br />
int&nbsp;&nbsp; (*(*func)(int&nbsp;&nbsp; *p))[5]; <br />
&nbsp;<br />
func 是一个函数指针，这类函数具有int* 类型的形参，返回值是指向数组的指针，所指向的数组的元素是具有5 个int 元素的数组。<br />
&nbsp;<br />
要注意有些复杂指针声明是非法的，例如：<br />
&nbsp;<br />
int&nbsp;&nbsp; func(void)&nbsp;&nbsp; [5]; <br />
&nbsp;<br />
func 是一个返回值为具有5 个int 元素的数组的函数。但C 语言的函数返回值不能为数组，这是因为如果允许函数返回值为数组，那么接收这个数组的内容的东西，也必须是一个数组，但C 语言的数组名是一个右值，它不能作为左值来接收另一个数组，因此函数返回值不能为数组。<br />
&nbsp;<br />
int&nbsp;&nbsp; func[5](void); <br />
&nbsp;<br />
func 是一个具有5 个元素的数组，这个数组的元素都是函数。这也是非法的，因为数组的元素除了类型必须一样外，每个元素所占用的内存空间也必须相同，显然函数是无法达到这个要求的，即使函数的类型一样，但函数所占用的空间通常是不相同的。<br />
&nbsp;<br />
作为练习，下面列几个复杂指针声明给读者自己来解析，答案放在第十章里。<br />
&nbsp;<br />
int&nbsp;&nbsp; (*(*func)[5][6])[7][8]; <br />
&nbsp;<br />
int&nbsp;&nbsp; (*(*(*func)(int&nbsp;&nbsp; *))[5])(int&nbsp;&nbsp; *); <br />
&nbsp;<br />
int&nbsp;&nbsp; (*(*func[7][8][9])(int*))[5]; <br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 实际当中，需要声明一个复杂指针时，如果把整个声明写成上面所示的形式，对程序可读性是一大损害。应该用typedef 来对声明逐层分解，增强可读性，例如对于声明：<br />
&nbsp;<br />
int&nbsp;&nbsp; (*(*func)(int&nbsp;&nbsp; *p))[5]; <br />
&nbsp;<br />
可以这样分解：<br />
&nbsp;<br />
typedef&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp; (*PARA)[5]; <br />
typedef&nbsp;&nbsp; PARA&nbsp;&nbsp; (*func)(int&nbsp;&nbsp; *); <br />
&nbsp;<br />
这样就容易看得多了。&nbsp; </font></p>
<p><font style="background-color: #cde9d1"><br />
本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/xiaojianpitt/archive/2009/10/30/4748427.aspx</font></p>
<img src ="http://www.blogjava.net/tinysun/aggbug/320072.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-05-04 21:33 <a href="http://www.blogjava.net/tinysun/archive/2010/05/04/320072.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>频繁分配释放内存导致的性能问题的分析[转]</title><link>http://www.blogjava.net/tinysun/archive/2010/03/28/316737.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sun, 28 Mar 2010 02:48:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/03/28/316737.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/316737.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/03/28/316737.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/316737.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/316737.html</trackback:ping><description><![CDATA[<strong>现象</strong><br />
1 压力测试过程中，发现被测对象性能不够理想，具体表现为： <br />
进程的系统态CPU消耗20，用户态CPU消耗10，系统idle大约70 <br />
2 用ps -o majflt,minflt -C program命令查看，发现majflt每秒增量为0，而minflt每秒增量大于10000。<br />
<br />
<strong>初步分析</strong><br />
majflt代表major fault，中文名叫大错误，minflt代表minor fault，中文名叫小错误。<br />
这两个数值表示一个进程自启动以来所发生的缺页中断的次数。<br />
当一个进程发生缺页中断的时候，进程会陷入内核态，执行以下操作： <br />
检查要访问的虚拟地址是否合法 <br />
查找/分配一个物理页 <br />
填充物理页内容（读取磁盘，或者直接置0，或者啥也不干） <br />
建立映射关系（虚拟地址到物理地址） <br />
重新执行发生缺页中断的那条指令 <br />
如果第3步，需要读取磁盘，那么这次缺页中断就是majflt，否则就是minflt。 <br />
此进程minflt如此之高，一秒10000多次，不得不怀疑它跟进程内核态cpu消耗大有很大关系。<br />
<br />
<strong>分析代码</strong><br />
查看代码，发现是这么写的：一个请求来，用malloc分配2M内存，请求结束后free这块内存。看日志，发现分配内存语句耗时10us，平均一条请求处理耗时1000us 。 原因已找到！ <br />
虽然分配内存语句的耗时在一条处理请求中耗时比重不大，但是这条语句严重影响了性能。要解释清楚原因，需要先了解一下内存分配的原理。 <br />
<br />
<strong>内存分配的原理</strong><br />
从操作系统角度来看，进程分配内存有两种方式，分别由两个系统调用完成：brk和mmap（不考虑共享内存）。brk是将数据段(.data)的最高地址指针_edata往高地址推，mmap是在进程的虚拟地址空间中（一般是堆和栈中间）找一块空闲的。这两种方式分配的都是虚拟内存，没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候，发生缺页中断，操作系统负责分配物理内存，然后建立虚拟内存和物理内存之间的映射关系。 <br />
在标准C库中，提供了malloc/free函数分配释放内存，这两个函数底层是由brk，mmap，munmap这些系统调用实现的。 <br />
下面以一个例子来说明内存分配的原理：<br />
<img alt="" src="http://images.csdn.net/20100325/c-1.jpg" /><br />
1进程启动的时候，其（虚拟）内存空间的初始布局如图1所示。其中，mmap内存映射文件是在堆和栈的中间（例如libc-2.2.93.so，其它数据文件等），为了简单起见，省略了内存映射文件。_edata指针（glibc里面定义）指向数据段的最高地址。 <br />
2进程调用A=malloc(30K)以后，内存空间如图2：malloc函数会调用brk系统调用，将_edata指针往高地址推30K，就完成虚拟内存分配。你可能会问：只要把_edata+30K就完成内存分配了？事实是这样的，_edata+30K只是完成虚拟地址的分配，A这块内存现在还是没有物理页与之对应的，等到进程第一次读写A这块内存的时候，发生缺页中断，这个时候，内核才分配A这块内存对应的物理页。也就是说，如果用malloc分配了A这块内容，然后从来不访问它，那么，A对应的物理页是不会被分配的。 <br />
3进程调用B=malloc(40K)以后，内存空间如图3. <br />
<br />
<img alt="" src="http://images.csdn.net/20100325/c-2.jpg" /><br />
4进程调用C=malloc(200K)以后，内存空间如图4：默认情况下，malloc函数分配内存，如果请求内存大于128K（可由M_MMAP_THRESHOLD选项调节），那就不是去推_edata指针了，而是利用mmap系统调用，从堆和栈的中间分配一块虚拟内存。这样子做主要是因为brk分配的内存需要等到高地址内存释放以后才能释放（例如，在B释放之前，A是不可能释放的），而mmap分配的内存可以单独释放。当然，还有其它的好处，也有坏处，再具体下去，有兴趣的同学可以去看glibc里面malloc的代码了。 <br />
5进程调用D=malloc(100K)以后，内存空间如图5. <br />
6进程调用free(C)以后，C对应的虚拟内存和物理内存一起释放 <br />
<img alt="" src="http://images.csdn.net/20100325/c-3.jpg" /><br />
<br />
7进程调用free(B)以后，如图7所示。B对应的虚拟内存和物理内存都没有释放，因为只有一个_edata指针，如果往回推，那么D这块内存怎么办呢？当然，B这块内存，是可以重用的，如果这个时候再来一个40K的请求，那么malloc很可能就把B这块内存返回回去了。 <br />
8进程调用free(D)以后，如图8所示。B和D连接起来，变成一块140K的空闲内存。 <br />
9默认情况下：当最高地址空间的空闲内存超过128K（可由M_TRIM_THRESHOLD选项调节）时，执行内存紧缩操作（trim）。在上一个步骤free的时候，发现最高地址空闲内存超过128K，于是内存紧缩，变成图9所示。<br />
<br />
真相大白<br />
说完内存分配的原理，那么被测模块在内核态cpu消耗高的原因就很清楚了：每次请求来都malloc一块2M的内存，默认情况下，malloc调用mmap分配内存，请求结束的时候，调用munmap释放内存。假设每个请求需要6个物理页，那么每个请求就会产生6个缺页中断，在2000的压力下，每秒就产生了10000多次缺页中断，这些缺页中断不需要读取磁盘解决，所以叫做minflt；缺页中断在内核态执行，因此进程的内核态cpu消耗很大。缺页中断分散在整个请求的处理过程中，所以表现为分配语句耗时（10us）相对于整条请求的处理时间（1000us）比重很小。<br />
<br />
解决办法<br />
将动态内存改为静态分配，或者启动的时候，用malloc为每个线程分配，然后保存在threaddata里面。但是，由于这个模块的特殊性，静态分配，或者启动时候分配都不可行。另外，Linux下默认栈的大小限制是10M，如果在栈上分配几M的内存，有风险。 <br />
禁止malloc调用mmap分配内存，禁止内存紧缩。<br />
在进程启动时候，加入以下两行代码：<br />
mallopt(M_MMAP_MAX, 0); // 禁止malloc调用mmap分配内存<br />
mallopt(M_TRIM_THRESHOLD, -1); // 禁止内存紧缩<br />
效果：加入这两行代码以后，用ps命令观察，压力稳定以后，majlt和minflt都为0。进程的系统态cpu从20降到10。<br />
<br />
小结<br />
可以用命令ps -o majflt minflt -C program来查看进程的majflt, minflt的值，这两个值都是累加值，从进程启动开始累加。在对高性能要求的程序做压力测试的时候，我们可以多关注一下这两个值。 <br />
如果一个进程使用了mmap将很大的数据文件映射到进程的虚拟地址空间，我们需要重点关注majflt的值，因为相比minflt，majflt对于性能的损害是致命的，随机读一次磁盘的耗时数量级在几个毫秒，而minflt只有在大量的时候才会对性能产生影响。
<img src ="http://www.blogjava.net/tinysun/aggbug/316737.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-03-28 10:48 <a href="http://www.blogjava.net/tinysun/archive/2010/03/28/316737.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【C\C++语言入门篇】-- 文件操作</title><link>http://www.blogjava.net/tinysun/archive/2010/03/10/315059.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Wed, 10 Mar 2010 07:22:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2010/03/10/315059.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/315059.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2010/03/10/315059.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/315059.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/315059.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 所谓文件（file）一般指存储在外部介质上数据的集合，比如我们经常使用的mp3、mp4、txt、bmp、jpg、exe、rmvb等等。这些文件各有各的用途，我们通常将它们存放在磁盘或者可移动盘等介质中。那么，为什么这里面又有这么多种格式的文件呢？原因很简单，它们各有各的用途，区分就在于这些文件里面存放的数据集合所遵循的存储规则不一样。举个例子比如bmp图片文件，为什么他能够表示一张图片，因为它有固...&nbsp;&nbsp;<a href='http://www.blogjava.net/tinysun/archive/2010/03/10/315059.html'>阅读全文</a><img src ="http://www.blogjava.net/tinysun/aggbug/315059.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2010-03-10 15:22 <a href="http://www.blogjava.net/tinysun/archive/2010/03/10/315059.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Bjarne Stroustrup 语录 --------我非常喜欢的文章</title><link>http://www.blogjava.net/tinysun/archive/2009/12/13/305778.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sun, 13 Dec 2009 05:00:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/12/13/305778.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/305778.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/12/13/305778.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/305778.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/305778.html</trackback:ping><description><![CDATA[<p><font style="background-color: #cce8cf">一、致读者</font></p>
<p><font style="background-color: #cce8cf">1．&nbsp; 在编程序时，你是在为你针对某个问题的解决方案中的思想建立起一种具体表示。让程序的结构尽可能地直接反映这些思想：<br />
&nbsp;&nbsp; ★.如果你能把&#8220;它&#8221;看成一个独立的概念，就把它做成一个类。<br />
&nbsp;&nbsp; ★.如果你能把&#8220;它&#8221;看成一个独立的实体，就把它做成某个类的一个对象。<br />
&nbsp;&nbsp; ★.如果两个类有共同的界面，将此界面做成一个抽象类。<br />
&nbsp;&nbsp; ★.如果两个类的实现有某些显著的共同东西，将这些共性做成一个基类。<br />
&nbsp;&nbsp; ★.如果一个类是一种对象的容器，将它做成一个模板。<br />
&nbsp;&nbsp; ★.如果一个函数实现对某容器的一个算法，将它做成为对一族容器可用的模板函数。<br />
&nbsp;&nbsp; ★.如果一组类、模板等相互之间有逻辑联系，将它们放进一个名字空间里。</font></p>
<p><font style="background-color: #cce8cf">2．&nbsp; 在你定义一个并不是实现某个像矩阵或复数这样的数学对象的类时，或者定义一个低层的类型如链接表的时候：<br />
&nbsp;&nbsp; ★.不要使用全局数据（使用成员）。<br />
&nbsp;&nbsp; ★.不要使用全局函数。<br />
&nbsp;&nbsp; ★.不要使用公用数据成员。<br />
&nbsp;&nbsp; ★.不要使用友元，除非为了避免a或c。<br />
&nbsp;&nbsp; ★.不要在一个类里面放&#8220;类型域&#8221;（指那种为了说明一个类所存储数据的情况而放置的标志域） ；采用虚函数。<br />
&nbsp;&nbsp; ★.不要使用在线函数(inline function)，除非作为效果显著的优化。</font></p>
<p><font style="background-color: #cce8cf">二、C++ 概览</font></p>
<p><font style="background-color: #cce8cf">1．&nbsp; 不用害怕，一切都会随着时间的推移而逐渐明朗起来。<br />
2．&nbsp; 你并不需要在知道了C++的所有细节之后才能写出好的C++程序。<br />
3．&nbsp; 请特别关注程序设计技术，而不是各种语言特征。</font></p>
<p><font style="background-color: #cce8cf">三、标准库概览</font></p>
<p><font style="background-color: #cce8cf">1．&nbsp; 不要像重新发明车轮那样企图做每件事；去使用库。<br />
2．&nbsp; 不要相信奇迹；要理解你的库能做什么，它们如何做，它们做时需要多大的代价。<br />
3．&nbsp; 当你遇到一个选择时，应该优先选择标准库而不是其他的库。<br />
4．&nbsp; 不要认为标准库对于任何事情都是最理想的。<br />
5．&nbsp; 切记#include 你所用到的功能的头文件。<br />
6．&nbsp; 记住，标准库的功能定义在名字空间std之中。<br />
7．&nbsp; 请用string，而不是char*。<br />
8．&nbsp; 如果怀疑，就用一个检查区间范围的向量（例如Vec）。<br />
9．&nbsp; vector&lt;T&gt; 、list&lt;T&gt;和 map&lt;key,value&gt; 都比T[] 好。<br />
10． 如果向一个容器中添加一个元素，用push_back() 或 back_inserter()。<br />
11． 采用对vector的push_back()，而不是对数组的realloc()。<br />
12． 在main()中捕捉公共的异常。</font></p>
<p><font style="background-color: #cce8cf">四、类型和声明</font></p>
<p><font style="background-color: #cce8cf">1．&nbsp; 保持较小的作用域。<br />
2．&nbsp; 不要在一个作用域和它外围的作用域里采用同样的名字。<br />
3．&nbsp; 在一个声明中只声明一个名字。<br />
4．&nbsp; 让常用的和局部的名字比较短，让不常用的和全局的名字比较长。<br />
5．&nbsp; 避免看起来类似的名字。<br />
6．&nbsp; 维持某种统一的命名风格。<br />
7．&nbsp; 仔细选择名字，反映其意义而不是反映实现方式。<br />
8．&nbsp; 如果所用的内部类型表示某种可能变化的值，请用typedef 为它定义一个有意义的名字。<br />
9．&nbsp; 用typedef为类型定义同义词，用枚举或类去定义新类型。<br />
10． 切记每个声明中都必须描述一个类型（没有&#8220;隐式的int&#8221;）。<br />
11． 避免有关字符数值的不必要假设。<br />
12． 避免有关整数大小的不必要假设。<br />
13． 避免有关浮点类型表示范围的不必要假设。<br />
14． 优先使用普通的int 而不是short int 或者long int。<br />
15． 优先使用double 而不是float 或者long double。<br />
16． 优先使用普通的 char 而不是 signed char或者 unsigned char。<br />
17． 避免做出有关对象大小的不必要假设。<br />
18． 避免无符号算术。<br />
19． 应该带着疑问去看待从signed 到unsigned ，或者从unsigned 到signed 的转换。<br />
20． 应该带着疑问去看待从浮点到整型的转换。<br />
21． 应该带着疑问去看待向较小类型的转换，如将int转换到char。</font></p>
<p><font style="background-color: #cce8cf">五、忠告</font></p>
<p><font style="background-color: #cce8cf">1．&nbsp; 避免非平凡的指针算术。<br />
2．&nbsp; 当心，不要超出数组的界线去写。<br />
3．&nbsp; 尽量使用0而不是NULL。<br />
4．&nbsp; 尽量使用vector 和valarray ，而不是内部（C风格）的数组。<br />
5．&nbsp; 尽量使用string而不是以0结尾的char 数组。<br />
6．&nbsp; 尽量少用普通的引用参数。<br />
7．&nbsp; 避免 void*，除了在某些低级代码里。<br />
8．&nbsp; 避免在代码中使用非平凡的文字量（&#8220;神秘的数&#8221;）。相反，应该定义和使用各种符号常量。</font></p>
<p><font style="background-color: #cce8cf"><br />
本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/youki1234/archive/2005/01/29/273434.aspx</font></p>
<img src ="http://www.blogjava.net/tinysun/aggbug/305778.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-12-13 13:00 <a href="http://www.blogjava.net/tinysun/archive/2009/12/13/305778.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ADL关联名字查找 </title><link>http://www.blogjava.net/tinysun/archive/2009/12/13/305777.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sun, 13 Dec 2009 04:45:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/12/13/305777.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/305777.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/12/13/305777.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/305777.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/305777.html</trackback:ping><description><![CDATA[<p>如果给定一个函数名，那么c++编译器如何去查找这个函数呢？<br />
1.普通的名字查找&nbsp;<br />
&nbsp;&nbsp; 对变量的调用，一般是按scope的大小来的<br />
</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">#include</span><span style="color: #000000">&lt;</span><span style="color: #000000">iostream</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" />#include</span><span style="color: #000000">&lt;</span><span style="color: #0000ff">string</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">using</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">namespace</span><span style="color: #000000">&nbsp;std;<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">namespace</span><span style="color: #000000">&nbsp;NS<br />
<img id="Codehighlighter1_71_106_Open_Image" onclick="this.style.display='none'; Codehighlighter1_71_106_Open_Text.style.display='none'; Codehighlighter1_71_106_Closed_Image.style.display='inline'; Codehighlighter1_71_106_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_71_106_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_71_106_Closed_Text.style.display='none'; Codehighlighter1_71_106_Open_Image.style.display='inline'; Codehighlighter1_71_106_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span id="Codehighlighter1_71_106_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_71_106_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">string</span><span style="color: #000000">&nbsp;x</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">namespace&nbsp;NS</span><span style="color: #000000">"</span><span style="color: #000000">;<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000"><br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">string</span><span style="color: #000000">&nbsp;x</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">global&nbsp;scope</span><span style="color: #000000">"</span><span style="color: #000000">;<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;A<br />
<img id="Codehighlighter1_143_355_Open_Image" onclick="this.style.display='none'; Codehighlighter1_143_355_Open_Text.style.display='none'; Codehighlighter1_143_355_Closed_Image.style.display='inline'; Codehighlighter1_143_355_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_143_355_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_143_355_Closed_Text.style.display='none'; Codehighlighter1_143_355_Open_Image.style.display='inline'; Codehighlighter1_143_355_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span id="Codehighlighter1_143_355_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_143_355_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">string</span><span style="color: #000000">&nbsp;x;<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" /></span><span style="color: #0000ff">public</span><span style="color: #000000">:<br />
<img id="Codehighlighter1_199_200_Open_Image" onclick="this.style.display='none'; Codehighlighter1_199_200_Open_Text.style.display='none'; Codehighlighter1_199_200_Closed_Image.style.display='inline'; Codehighlighter1_199_200_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_199_200_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_199_200_Closed_Text.style.display='none'; Codehighlighter1_199_200_Open_Image.style.display='inline'; Codehighlighter1_199_200_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A():x(</span><span style="color: #000000">"</span><span style="color: #000000">class&nbsp;scope</span><span style="color: #000000">"</span><span style="color: #000000">)</span><span id="Codehighlighter1_199_200_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_199_200_Open_Text"><span style="color: #000000">{}</span></span><span style="color: #000000">;<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img id="Codehighlighter1_220_301_Open_Image" onclick="this.style.display='none'; Codehighlighter1_220_301_Open_Text.style.display='none'; Codehighlighter1_220_301_Closed_Image.style.display='inline'; Codehighlighter1_220_301_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_220_301_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_220_301_Closed_Text.style.display='none'; Codehighlighter1_220_301_Open_Image.style.display='inline'; Codehighlighter1_220_301_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;f()</span><span id="Codehighlighter1_220_301_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_220_301_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">string</span><span style="color: #000000">&nbsp;x</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">local&nbsp;scope</span><span style="color: #000000">"</span><span style="color: #000000">;<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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 />
<img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img id="Codehighlighter1_319_353_Open_Image" onclick="this.style.display='none'; Codehighlighter1_319_353_Open_Text.style.display='none'; Codehighlighter1_319_353_Closed_Image.style.display='inline'; Codehighlighter1_319_353_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_319_353_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_319_353_Closed_Text.style.display='none'; Codehighlighter1_319_353_Open_Image.style.display='inline'; Codehighlighter1_319_353_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;g()</span><span id="Codehighlighter1_319_353_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_319_353_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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 />
<img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;}</span></span><span style="color: #000000"><br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000">;<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;B<br />
<img id="Codehighlighter1_367_589_Open_Image" onclick="this.style.display='none'; Codehighlighter1_367_589_Open_Text.style.display='none'; Codehighlighter1_367_589_Closed_Image.style.display='inline'; Codehighlighter1_367_589_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_367_589_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_367_589_Closed_Text.style.display='none'; Codehighlighter1_367_589_Open_Image.style.display='inline'; Codehighlighter1_367_589_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span id="Codehighlighter1_367_589_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_367_589_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">:<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;f()<br />
<img id="Codehighlighter1_426_483_Open_Image" onclick="this.style.display='none'; Codehighlighter1_426_483_Open_Text.style.display='none'; Codehighlighter1_426_483_Closed_Image.style.display='inline'; Codehighlighter1_426_483_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_426_483_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_426_483_Closed_Text.style.display='none'; Codehighlighter1_426_483_Open_Image.style.display='inline'; Codehighlighter1_426_483_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_426_483_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_426_483_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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 />
<img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;g()<br />
<img id="Codehighlighter1_526_587_Open_Image" onclick="this.style.display='none'; Codehighlighter1_526_587_Open_Text.style.display='none'; Codehighlighter1_526_587_Closed_Image.style.display='inline'; Codehighlighter1_526_587_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_526_587_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_526_587_Closed_Text.style.display='none'; Codehighlighter1_526_587_Open_Image.style.display='inline'; Codehighlighter1_526_587_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_526_587_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_526_587_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">NS::x</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">endl;<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000">;<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;main()<br />
<img id="Codehighlighter1_604_674_Open_Image" onclick="this.style.display='none'; Codehighlighter1_604_674_Open_Text.style.display='none'; Codehighlighter1_604_674_Closed_Image.style.display='inline'; Codehighlighter1_604_674_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_604_674_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_604_674_Closed_Text.style.display='none'; Codehighlighter1_604_674_Open_Image.style.display='inline'; Codehighlighter1_604_674_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span id="Codehighlighter1_604_674_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_604_674_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A&nbsp;a;<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;B&nbsp;b;<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.f();a.g();<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.f();b.g();<br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000"><br />
<img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"  alt="" /></span></div>
<p>&nbsp;</p>
<ul>
    <li>首先调用local scope的
    <li>接着调用class scope的
    <li>最后才调用global scope的
    <li>如果直接有用限定符，则调用限定符的，无论是namespace 限定符还是class限定符 </li>
</ul>
<p>函数名字的查找，除了local scope的，基本同上，有一点例外的是，则在下面ADL中说明<br />
<br />
2.关联名字查找 (Argument Dependent Lookup)<br />
在说明前要明确2个概念<br />
</p>
<ul>
    <li>关联(dependent name)：不能解析的名字就叫关联名，这个一般同模版有关，比如template&lt;class&nbsp;T&gt; A{T t;};&nbsp;中，t就是关联名，它在模版编译的第一阶段是无法解析的，只有到第二阶段，用实际参数来实例化的时候才知道&nbsp;
    <li>限定名(qualified name): 指变量名或函数名前有类名前缀，或者被对象，指针修饰： Class::f() //类名前缀&nbsp; x.f() //对象修饰 p-&gt;f() //指针修饰 </li>
</ul>
<p>而ADL要解决的问题是对非限定名的查找问题（限定名可以根据相应的限定来查找）： 当出现了对某个非限定函数的调用，而该非限定函数却没有在一个（标准）作用域内进行声明时（简单的讲，该函数只声明在某个namespace，而你又没有引入这个namespace)，编译器就会寻找它的每一个参数的名字空间来进行匹配。ADL是为了简化函数调用，不过事实上它有点破坏了namespace的封装。<br />
比如以下函数调用<br />
&nbsp;&nbsp;&nbsp;std::string s("hello");<br />
&nbsp;&nbsp; std::cout&lt;&lt;s&lt;&lt;std::endl;<br />
程序中没有指定使用哪一个operator&lt;&lt;函数，程序员当然不想输入<br />
&nbsp;&nbsp;std::operator&lt;&lt;(std::operator(std::cout,s),std::endl);<br />
这时，ADL根据s查找s的namespace,并查找相应的operator&lt;&lt;</p>
<img src ="http://www.blogjava.net/tinysun/aggbug/305777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-12-13 12:45 <a href="http://www.blogjava.net/tinysun/archive/2009/12/13/305777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ADL(Koenig)查找</title><link>http://www.blogjava.net/tinysun/archive/2009/12/13/305771.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sun, 13 Dec 2009 03:37:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/12/13/305771.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/305771.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/12/13/305771.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/305771.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/305771.html</trackback:ping><description><![CDATA[<p><font style="background-color: #cce8cf">ADL(Koenig) 查找 </font></p>
<p><font style="background-color: #cce8cf">ADL ，参数相关查找，也称作为 Koenig 查找（以 Andrew Koenig 的名字命名），是指在编译器对无限定域的函数调用进行名字查找时，所应用的一种查找规则。 </font></p>
<p><font style="background-color: #cce8cf">首先来看一个函数所在的域的分类： </font></p>
<p><font style="background-color: #cce8cf">1 ：类域（函数作为某个类的成员函数（静态或非静态）） </font></p>
<p><font style="background-color: #cce8cf">2 ：名字空间域 </font></p>
<p><font style="background-color: #cce8cf">3 ：全局域 </font></p>
<p><font style="background-color: #cce8cf">而 Koenig 查找，它的规则就是当编译器对无限定域的函数调用进行名字查找时，除了当前名字空间域以外，也会把函数参数类型所处的名字空间 加入查找的范围。 </font></p>
<p><font style="background-color: #cce8cf">ADL 就是为了确保使用类型 X 的对象 x 时能够像使用 X 的成员函数一样简单 (ensure that code that uses an object x of type X can use its nonmember function interface as easily as it can use member functions) 。 </font></p>
<p><font style="background-color: #cce8cf">根据 ADL 规则，如果非成员函数想和类型一起被使用，应该将它们置于同一个名字空间中。换句话说，和类型 X 放在同一名字空间下的非成员函数，也是 X 接口的一部分。 ( 常见的有 &lt;&lt;or&gt;&gt; 操作符 ) </font></p>
<p><font style="background-color: #cce8cf">示例： </font></p>
<p><font style="background-color: #cce8cf">#include &lt;iostream&gt; </font></p>
<p><font style="background-color: #cce8cf">//class N&nbsp;&nbsp;&nbsp;&nbsp; // 类域 </font></p>
<p><font style="background-color: #cce8cf">//{ </font></p>
<p><font style="background-color: #cce8cf">//public : </font></p>
<p><font style="background-color: #cce8cf">//&nbsp;&nbsp;&nbsp;&nbsp; enum E {e1}; </font></p>
<p><font style="background-color: #cce8cf">//&nbsp;&nbsp;&nbsp;&nbsp; void f(E) </font></p>
<p><font style="background-color: #cce8cf">//&nbsp;&nbsp;&nbsp;&nbsp; { </font></p>
<p><font style="background-color: #cce8cf">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; "N::f(N::E) called\n"; </font></p>
<p><font style="background-color: #cce8cf">//&nbsp;&nbsp;&nbsp;&nbsp; } </font></p>
<p><font style="background-color: #cce8cf">//}; </font></p>
<p><font style="background-color: #cce8cf">namespace N{&nbsp;&nbsp; // 名字空间域 </font></p>
<p><font style="background-color: #cce8cf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enum E {e1}; </font></p>
<p><font style="background-color: #cce8cf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void f(E){ </font></p>
<p><font style="background-color: #cce8cf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; "N::f(N::E) called\n"; </font></p>
<p><font style="background-color: #cce8cf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </font></p>
<p><font style="background-color: #cce8cf">} </font></p>
<p><font style="background-color: #cce8cf">void f(int) </font></p>
<p><font style="background-color: #cce8cf">{ </font></p>
<p><font style="background-color: #cce8cf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; " ::f(int) called\n"; </font></p>
<p><font style="background-color: #cce8cf">} </font></p>
<p><font style="background-color: #cce8cf">&nbsp; </font></p>
<p><font style="background-color: #cce8cf">int main() </font></p>
<p><font style="background-color: #cce8cf">{ </font></p>
<p><font style="background-color: #cce8cf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ::f(N::e1);&nbsp;&nbsp;&nbsp;&nbsp; // 受限函数，禁用 ADL&nbsp; // 输出 ::f(int) called </font></p>
<p><font style="background-color: #cce8cf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f(N::e1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 普通查找到 f(); </font></p>
<p><font style="background-color: #cce8cf">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0; </font></p>
<p><font style="background-color: #cce8cf">} </font></p>
<p><font style="background-color: #cce8cf">&nbsp; </font></p>
<p><font style="background-color: #cce8cf">上述例子，如果 N 为 class ，输出为： ::f(int) called ；如果 N 为名字空间，输出： N::f(N::E) called 。 </font></p>
<p><font style="background-color: #cce8cf">也就是说 ADL 仅会将参数所在的名字空间中的函数名字加入查找范围。 </font></p>
<p><font style="background-color: #cce8cf">调用函数时，显式地限定名字空间将禁用 ADL 查找 ，加快解析过程。 </font></p>
<p><font style="background-color: #cce8cf"></font>&nbsp;</p>
<p><font style="background-color: #cce8cf">Argument&nbsp;Dependent&nbsp;Lookup&nbsp;(ADL)解析<br />
<br />
</p>
<div id="blog_text">
<p>ADL，参数相关查找，也称作为Koenig查找（以Andrew Koenig的名字命名，有兴趣可以看Scott Meyer的文章<em><span style="font-style: normal"><a href="http://www.artima.com/cppsource/top_cpp_people.html"><em>The Most Important C++ People...Ever</em></a></span></em>），是指在编译器对无限定域的函数调用进行名字查找时，所应用的一种查找规则。</p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 5.4pt; border-top: windowtext 0.5pt solid; padding-left: 5.4pt; background: rgb(230,230,230) 0% 50%; padding-bottom: 4px; border-left: windowtext 0.5pt solid; width: 95%; padding-top: 4px; border-bottom: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
<div><img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: rgb(0,0,0)">f(x, y, z); </span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)"> unqualified</span><span style="color: rgb(0,128,0)"><br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: rgb(0,0,0)">N::f(x, y, z); </span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)"> qualified</span></div>
</div>
<br />
<div>
<div>上面的函数调用，第一个f就是无限定域的函数调用，第二个则限定了在名字空间N里面，也是说使用了完全限定名。</div>
<div>我们首先来看一个函数所在的域的分类：</div>
<div>1：类域（函数作为某个类的成员函数（静态或非静态））</div>
<div>2：名字空间域</div>
<div>3：全局域</div>
<div>而Koenig查找，它的规则就是当编译器对无限定域的函数调用进行名字查找时，除了当前名字空间域以外，也会把函数参数类型所处的名字空间加入查找的范围。</div>
<div>Herb提供的解释（Exceptional C++, Item 31）</div>
<p><em><span style="font-size: 9pt; color: gray">Koenig Lookup(simplified): If you supply a function argument of class type (here <tt><font face="新宋体">x</font></tt>, of type <tt><font face="新宋体">A::X</font></tt>), then to look up the correct function name the compiler considers matching names in the namespace (here <tt><font face="新宋体">A</font></tt>) containing the argument's type.</span></em></p>
<div>请看下面的例程：</div>
<div>
<div>
<div style="border-right: windowtext 0.5pt solid; padding-right: 5.4pt; border-top: windowtext 0.5pt solid; padding-left: 5.4pt; background: rgb(230,230,230) 0% 50%; padding-bottom: 4px; border-left: windowtext 0.5pt solid; width: 95%; padding-top: 4px; border-bottom: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
<div><img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: rgb(0,0,0)">#include </span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">iostream</span><span style="color: rgb(0,0,0)">&gt;</span><span style="color: rgb(0,0,0)"><br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: rgb(0,0,255)">using</span><span style="color: rgb(0,0,255)">namespace</span><span style="color: rgb(0,0,0)"> std;<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top"  alt="" /> <br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: rgb(0,0,255)">namespace</span><span style="color: rgb(0,0,0)"> Koenig<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img style="display: none" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span style="color: rgb(0,0,0)">{<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">class</span><span style="color: rgb(0,0,0)"> KoenigArg<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img style="display: none" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,0)">{<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,0)">:<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ostream</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)"> print(ostream</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,255)">out</span><span style="color: rgb(0,0,0)">) </span><span style="color: rgb(0,0,255)">const</span><span style="color: rgb(0,0,0)"><br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img style="display: none" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,0)">{<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">out</span><span style="color: rgb(0,0,0)">&lt;&lt;</span><span style="color: rgb(0,0,0)">member_</span><span style="color: rgb(0,0,0)">&lt;&lt;</span><span style="color: rgb(0,0,0)">endl;<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></span><span style="color: rgb(0,0,0)"><br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" /> <br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img style="display: none" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KoenigArg(</span><span style="color: rgb(0,0,255)">int</span><span style="color: rgb(0,0,0)"> member </span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">5</span><span style="color: rgb(0,0,0)">) : member_(member)</span><span style="color: rgb(0,0,0)">{}</span><span style="color: rgb(0,0,0)"><br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">private</span><span style="color: rgb(0,0,0)">:<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">int</span><span style="color: rgb(0,0,0)"> member_;<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp; }</span></span><span style="color: rgb(0,0,0)">;<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" /> <br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp; inline ostream</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,255)">operator</span><span style="color: rgb(0,0,0)">&lt;&lt;</span><span style="color: rgb(0,0,0)">(ostream</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,255)">out</span><span style="color: rgb(0,0,0)">, </span><span style="color: rgb(0,0,255)">const</span><span style="color: rgb(0,0,0)"> KoenigArg</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)"> kArg)<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img style="display: none" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,0)">{<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)"> kArg.print(</span><span style="color: rgb(0,0,255)">out</span><span style="color: rgb(0,0,0)">);<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp; }</span></span><span style="color: rgb(0,0,0)"><br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: rgb(0,0,0)"><br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top"  alt="" /> <br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: rgb(0,0,255)">int</span><span style="color: rgb(0,0,0)"> main()<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img style="display: none" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span style="color: rgb(0,0,0)">{<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp; Koenig::KoenigArg karg(<span style="color: rgb(0,0,0)">10</span><span style="color: rgb(0,0,0)">);<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp; cout</span><span style="color: rgb(0,0,0)">&lt;&lt;</span><span style="color: rgb(0,0,0)">karg;<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" /> <br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">char</span><span style="color: rgb(0,0,0)"> c;cin</span><span style="color: rgb(0,0,0)">&gt;&gt;</span><span style="color: rgb(0,0,0)">c;<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span></div>
</div>
</div>
<p>我们通常都会写如上的代码，使用operator&lt;&lt;打印对象的状态，但是ostream&amp; operator&lt;&lt;(ostream&amp; out, const KoenigArg&amp; kArg) 的定义是处于名字空间Koenig，为什么编译器在解析main函数（全局域）里面的operator&lt;&lt;调用时，它能够正确定位到Koenig名字空间里面的operator&lt;&lt;？这是因为根据Koenig查找规则，编译器需要把参数类型KoenigArg所在的名字空间Koenig也加入对operator&lt;&lt;调用的名字查找范围中。</p>
<p>如果没有Koenig查找规则，我们就无法直接写cout&lt;&lt;karg;，而是需要写类似Koenig::operator&lt;&lt;(std::cout, karg); 这样的代码（使用完全限定名）。嗯，即不直观也不方便是吗？更重要的是如果我们写的是模版代码，在模版参数还没有实例化之前，我们根本就不知道参数所处的名字空间，比如：</p>
<div>
<div style="border-right: windowtext 0.5pt solid; padding-right: 5.4pt; border-top: windowtext 0.5pt solid; padding-left: 5.4pt; background: rgb(230,230,230) 0% 50%; padding-bottom: 4px; border-left: windowtext 0.5pt solid; width: 95%; padding-top: 4px; border-bottom: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
<div><img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: rgb(0,0,0)">template</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">typename T</span><span style="color: rgb(0,0,0)">&gt;</span><span style="color: rgb(0,0,255)">void</span><span style="color: rgb(0,0,0)"> print(</span><span style="color: rgb(0,0,255)">const</span><span style="color: rgb(0,0,0)"> T</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)"> value)<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img style="display: none" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span style="color: rgb(0,0,0)">{<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp; std::cout<span style="color: rgb(0,0,0)">&lt;&lt;</span><span style="color: rgb(0,0,0)">value;<br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: rgb(0,0,0)"><br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top"  alt="" /> <br />
<img src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top"  alt="" />print(karg);</span></div>
</div>
</div>
<div>
<div>很显然，你的模版代码根本无法确认T是来自那个名字空间，直到编译器对模版实例化（print(karg); 被调用）。</div>
<div>对Koenig查找规则的一个异议是，由于Koenig查找规则的存在，处于某个名字空间的函数调用的重载决议会受到另外一个名字空间的自由函数所影响，仅仅是由于它使用了另外一个名字空间的类型作为参数。在这样的规则下，名字空间看起来不像我们一般所想象的那样是完全封闭和独立的。</div>
<div>我们应该怎么解释这样的异议呢？这样隐讳的影响或者依赖性是合理的吗？Herb认为，如果我们把另外一个名字空间的自由函数（非类成员函数）也看作是它所涉及的类型的接口的一部分，很显然，它应该参与这样的重载决议，这样的跨越名字空间的影响是合理的。从而导出了Herb在传统类定义之上的一个更详细和完整的解释（请参考Exceptional C++, Item 32）。</div>
<div>传统的类定义：</div>
<p style="margin-left: 21pt"><em><span style="font-size: 9pt; color: gray">A class describes a set of data, along with the functions that operate on that data.</em></span></p>
<div style="margin-left: 21pt"><em><span style="font-size: 9pt; color: gray">一个类描述了数据的集合以及操作这些数据的函数。</span></em></div>
<div>Herb的类定义，称之为接口准则（Interface Principle）：</div>
<div style="margin-left: 21pt"><em><span style="font-size: 9pt; color: gray">For a class X, all functions, including free functions, that both</span></em></div>
<div style="margin-left: 21pt; text-indent: 21pt"><em><span style="font-size: 9pt; color: gray">"Mention" X</span></em></div>
<div style="margin-left: 21pt; text-indent: 21pt"><em><span style="font-size: 9pt; color: gray">Are "supplied with" X</span></em></div>
<p style="margin-left: 21pt"><em><span style="font-size: 9pt; color: gray">are logically part of X, because they form part of the interface of X.</span></em></p>
<div style="margin-left: 21pt"><em><span style="font-size: 9pt; color: gray">对应类</span></em><em><span style="font-size: 9pt; color: gray">X</span></em><em><span style="font-size: 9pt; color: gray">来说，所有函数，包括自由函数，只要它们</span></em></div>
<div style="margin-left: 21pt"><em><span style="font-size: 9pt; color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></em><em><span style="font-size: 9pt; color: gray">提及</span></em><em><span style="font-size: 9pt; color: gray">X</span></em><em><span style="font-size: 9pt; color: gray">（跟</span></em><em><span style="font-size: 9pt; color: gray">X</span></em><em><span style="font-size: 9pt; color: gray">有关）</span></em></div>
<div style="margin-left: 21pt"><em><span style="font-size: 9pt; color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></em><em><span style="font-size: 9pt; color: gray">与</span></em><em><span style="font-size: 9pt; color: gray">X</span></em><em><span style="font-size: 9pt; color: gray">一起提供</span></em></div>
<div style="margin-left: 21pt"><em><span style="font-size: 9pt; color: gray">都在逻辑上被认为是</span></em><em><span style="font-size: 9pt; color: gray">X</span></em><em><span style="font-size: 9pt; color: gray">的一部分，因为它们是</span></em><em><span style="font-size: 9pt; color: gray">X</span></em><em><span style="font-size: 9pt; color: gray">的接口的一部分。</span></em></div>
<div>关于Koenig查找，我们该说的都说了吗？其实未然，之前所描述的只是Koenig查找一般可能发生的状况，当Koenig查找规则和C++ 原来的Ordinal Lookup（OL，顺序查找规则）混合在一起的时候，它们之间的组合所产生的状况要比之前的例子复杂的多&#8230;&#8230;</div>
</div>
</div>
</div>
</div>
</font>
<img src ="http://www.blogjava.net/tinysun/aggbug/305771.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-12-13 11:37 <a href="http://www.blogjava.net/tinysun/archive/2009/12/13/305771.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 转 C++编译器的函数编译流程 </title><link>http://www.blogjava.net/tinysun/archive/2009/12/13/305768.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sun, 13 Dec 2009 03:15:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/12/13/305768.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/305768.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/12/13/305768.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/305768.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/305768.html</trackback:ping><description><![CDATA[<p><font style="background-color: #cce8cf">C++ 中的类型查找过程相对简单，基本上就是名字查找，这里不再介绍。 </font></p>
<p><font style="background-color: #cce8cf">对于&nbsp; .cpp&nbsp; 文件中调用的一个函数&nbsp; (&nbsp; 成员函数&nbsp; ),&nbsp; 编译器主要做了下面三件事情&nbsp; : </font></p>
<p><font style="background-color: #cce8cf">1&nbsp; 名字查找&nbsp; .&nbsp; 先在所在编译单元中可见名字实体 中进行名字查找&nbsp; . (1)&nbsp; 类成员函数优先&nbsp; (&nbsp; 对象所在的类&nbsp; -&gt;&nbsp; 基类&nbsp; ).&nbsp; 一经找到就停止查找&nbsp; . 如果没有&nbsp; ,(2)&nbsp; 在相应的名字空间中做进一步的搜索&nbsp; ;&nbsp; 如果还没有&nbsp; ,&nbsp; 会根据&nbsp; (3)&nbsp; 函数参数所在的名字空间中查找&nbsp; (keoning&nbsp; 查找&nbsp; ). </font></p>
<p><font style="background-color: #cce8cf">2&nbsp; 重载决议&nbsp; .&nbsp; 根据所找到的名字进行重载决议&nbsp; ,&nbsp; 根据参数最匹配原则选择相应的函数&nbsp; . </font></p>
<p><font style="background-color: #cce8cf">3&nbsp; 可访问性检查&nbsp; .&nbsp; 用以确定被选中的函数是否可以被调用&nbsp; . </font></p>
<p><font style="background-color: #cce8cf">说明&nbsp; : </font></p>
<p><font style="background-color: #cce8cf">1)&nbsp; 根据第一条&nbsp; ,&nbsp; 显然&nbsp; ,&nbsp; 如果类型想和非成员函数一起工作&nbsp; ,&nbsp; 那么它们应该放在同一个名字空间中&nbsp; .&nbsp; 比如&nbsp; ,&nbsp; 一般类型的重载运算符和参数类型放在同一个头文件中&nbsp; /&nbsp; 或者同一个名字空间下&nbsp; . </font></p>
<p><font style="background-color: #cce8cf">2)&nbsp; 函数特化模板不参与重载决议&nbsp; ,&nbsp; 因此&nbsp; ,&nbsp; 如果想运用某个函数的特化&nbsp; ,&nbsp; 最好的方法是重载该函数&nbsp; ,&nbsp; 在实现中采用该特化来工作&nbsp; . </font></p>
<p><font style="background-color: #cce8cf">3)&nbsp; 重载决议发生的可访问性检查之前&nbsp; .&nbsp; 正因如此&nbsp; ,&nbsp; 如果私有函数不幸参与了重载&nbsp; ,&nbsp; 并且被选中的话&nbsp; ,&nbsp; 最终也会出现无法访问的编译提示&nbsp; .&nbsp; 这常常隐含二义性&nbsp; ,&nbsp; 这样设计也不合理&nbsp; .&nbsp; 换句话说&nbsp; ,&nbsp; 私有参数&nbsp; ,&nbsp; 在名字查找和重载时并非是&nbsp; &#8221;&nbsp; 私有的&nbsp; &#8221;. </font></p>
<p><font style="background-color: #cce8cf">&nbsp; </font></p>
<p><font style="background-color: #cce8cf">以&nbsp; c.Twice&nbsp; （&nbsp; 21&nbsp; ）的函数调用为例： </font></p>
<p><font style="background-color: #cce8cf">a)&nbsp; 名字查找：编译器会首先寻找一个至少包含一个名字为&nbsp; Twice&nbsp; 的实体作用域（类，文件，或者名字空间），并将其中的候选实体列表。例子中，编译器首先从对象&nbsp; c&nbsp; 所在的类实体中进行查找，找到就停止；如果没找到就会依次在其基类和外围的名字空间&nbsp;&nbsp; 中查找 ，直到找到一个至少含有一个候选函数的作用域。两点需要注意：&nbsp; 1)&nbsp; 只要找到一个实体就停止查找&nbsp;&nbsp; ，所以并非所有的同名函数都会被考虑；&nbsp; 2)&nbsp; 参数所在名字空间也属于查找范围 (keoning&nbsp; 准则&nbsp; )&nbsp; 。 </font></p>
<p><font style="background-color: #cce8cf">b)&nbsp; 重载决议：从所找到的候选重载函数列表中选出唯一最佳匹配&nbsp;&nbsp; 。如不唯一，就存在二义性。注意：&nbsp; 1)&nbsp; 这是基于名字查找结果的；&nbsp; 2)&nbsp; 特化的模板函数不参与重载。 </font></p>
<p><font style="background-color: #cce8cf">c)&nbsp; 可访问性检查：确定所选出的函数是否可访问。这是最后一步，晚于重载决议。 </font></p>
<p><font style="background-color: #cce8cf"></font>&nbsp;</p>
<p><font style="background-color: #cce8cf">本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/zhenjing/archive/2009/06/25/4299002.aspx</font></p>
<img src ="http://www.blogjava.net/tinysun/aggbug/305768.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-12-13 11:15 <a href="http://www.blogjava.net/tinysun/archive/2009/12/13/305768.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++调用本类的构造函数</title><link>http://www.blogjava.net/tinysun/archive/2009/12/12/305706.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Sat, 12 Dec 2009 06:45:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/12/12/305706.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/305706.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/12/12/305706.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/305706.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/305706.html</trackback:ping><description><![CDATA[一个继承类的构造函数首先要调用基类的构造函数。这没有什么需要说明的。<br />
本文要说的是当调用本类自己的构造函数时，将会产生什么行为。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通常情况下，我们只通过new或继承来调用一个类的构造函数，因为我们在类函数列表中看不到构造函数，然而在类函数中，是可以调用构造函数的。假设我们有构造函数A和构造函数B，那么在A中调用B就是一个很自然的想法。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 但是请注意：这种写法不会达到你期望的效果（无非是偷懒喽），而且会使你的程序出现意想不到的错误。:(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 请看下面一个例子：<br />
// 研究观察C++一种有意思的构造析构函数调用现象
<p>// 现象<br />
// 在构造函数A中调用重载的构造函数B<br />
// 结论<br />
// 在B被调用结束(A未结束)时已经有一次析构函数被调用</p>
<p>// 测试平台<br />
// 1.Win2K + VC6<br />
// 2.Linux + gcc</p>
<p><br />
<font color="#0000ff">#include &lt;stdio.h&gt;</font></p>
<p><font color="#0000ff">class CTest<br />
{<br />
public:<br />
&nbsp;&nbsp; CTest() {<br />
&nbsp;&nbsp;&nbsp;&nbsp; CTest(0);<br />
&nbsp;&nbsp;&nbsp;<font color="#339966"> //已经调用析构函数<br />
</font>&nbsp;&nbsp;&nbsp;&nbsp; printf("CTest()\r\n");<br />
&nbsp;&nbsp; }<br />
CTest(int i) {<br />
&nbsp;&nbsp;&nbsp;&nbsp; CTest(i, 0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#008080">//已经调用析构函数<br />
</font>&nbsp;&nbsp;&nbsp;&nbsp; printf("CTest(%d)\r\n", i);<br />
}<br />
CTest(int i, int j) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("CTest(%d, %d)\r\n", i, j);<br />
}<br />
virtual ~CTest(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_CTestCount++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf(" ~CTest() m_CTestCount = %d\r\n", m_CTestCount);<br />
}<br />
static int m_CTestCount;<br />
};<br />
int CTest::m_CTestCount = 0;<br />
int main()<br />
{<br />
CTest cT;<br />
printf("main()\r\n");<br />
<font color="#008080">//调用析构函数<br />
</font>return 0;<br />
}</font></p>
<p><font color="#008080">/*<br />
//程序运行输出<br />
CTest(0, 0)<br />
~CTest() m_CTestCount = 1<br />
CTest(0)<br />
~CTest() m_CTestCount = 2<br />
CTest()<br />
main()<br />
~CTest() m_CTestCount = 3<br />
//程序运行输出<br />
*/</font></p>
<p>=======================================<br />
出现这种结果的原因是什么呢？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当直接调用类的构造函数时，将产生一个A类型的临时对象，然后又马上被销毁。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 所以当在构造函数A中调用构造函数B时，也不会对本类的类变量进行初始化，导致的结果就是，构造函数A调用了B之后，本类的类变量还是没有被初始化，当A继续对这些类变量进行操作时，将出现对未初始化的空间进行访问的错误。</p>
<p>=======================================<br />
直接调用构造函数有没有用呢？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 既然直接调用可以产生一个临时对象，然后又马上被销毁。那么我们就可以把这种特点用于传参。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class A 有一个构造函数 A(int x)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void foo(A a);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 就可以 foo(A(10));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 此外对于 vector ve; ve.push_back(A(10)); 等容器操作也是有用的。 </p>
<img src ="http://www.blogjava.net/tinysun/aggbug/305706.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-12-12 14:45 <a href="http://www.blogjava.net/tinysun/archive/2009/12/12/305706.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++成员函数的重载、覆盖与隐藏</title><link>http://www.blogjava.net/tinysun/archive/2009/12/11/305609.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Fri, 11 Dec 2009 09:08:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/12/11/305609.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/305609.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/12/11/305609.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/305609.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/305609.html</trackback:ping><description><![CDATA[<p>&lt;转&gt;<br />
</p>
<p>成员函数的重载、覆盖与隐藏<br />
成员函数的重载、覆盖（override）与隐藏很容易混淆，C++程序员必须要搞清楚<br />
概念，否则错误将防不胜防。<br />
8.2.1 重载与覆盖<br />
成员函数被重载的特征：<br />
（1）相同的范围（在同一个类中）；<br />
（2）函数名字相同；<br />
（3）参数不同；<br />
（4）virtual 关键字可有可无。<br />
覆盖是指派生类函数覆盖基类函数，特征是：<br />
（1）不同的范围（分别位于派生类与基类）；<br />
（2）函数名字相同；<br />
（3）参数相同；<br />
（4）基类函数必须有virtual 关键字。<br />
示例8-2-1 中，函数Base::f(int)与Base::f(float)相互重载，而Base::g(void)<br />
被Derived::g(void)覆盖。<br />
#include &lt;iostream.h&gt;<br />
class Base<br />
{<br />
public:<br />
void f(int x){ cout &lt;&lt; "Base::f(int) " &lt;&lt; x &lt;&lt; endl; }<br />
void f(float x){ cout &lt;&lt; "Base::f(float) " &lt;&lt; x &lt;&lt; endl; }<br />
virtual void g(void){ cout &lt;&lt; "Base::g(void)" &lt;&lt; endl;}<br />
};<br />
class Derived : public Base<br />
{<br />
public:<br />
virtual void g(void){ cout &lt;&lt; "Derived::g(void)" &lt;&lt; endl;}<br />
};<br />
void main(void)<br />
{<br />
Derived d;<br />
Base *pb = &amp;d;<br />
pb-&gt;f(42); // Base::f(int) 42</p>
<p>pb-&gt;f(3.14f); // Base::f(float) 3.14<br />
pb-&gt;g(); // Derived::g(void)<br />
}<br />
示例8-2-1 成员函数的重载和覆盖<br />
8.2.2 令人迷惑的隐藏规则<br />
本来仅仅区别重载与覆盖并不算困难，但是C++的隐藏规则使问题复杂性陡然增加。<br />
这里&#8220;隐藏&#8221;是指派生类的函数屏蔽了与其同名的基类函数，规则如下：<br />
（1）如果派生类的函数与基类的函数同名，但是参数不同。此时，不论有无virtual<br />
关键字，基类的函数将被隐藏（注意别与重载混淆）。<br />
（2）如果派生类的函数与基类的函数同名，并且参数也相同，但是基类函数没有virtual<br />
关键字。此时，基类的函数被隐藏（注意别与覆盖混淆）。<br />
示例程序8-2-2（a）中：<br />
（1）函数Derived::f(float)覆盖了Base::f(float)。<br />
（2）函数Derived::g(int)隐藏了Base::g(float)，而不是重载。<br />
（3）函数Derived::h(float)隐藏了Base::h(float)，而不是覆盖。<br />
#include &lt;iostream.h&gt;<br />
class Base<br />
{<br />
public:<br />
virtual void f(float x){ cout &lt;&lt; "Base::f(float) " &lt;&lt; x &lt;&lt; endl; }<br />
void g(float x){ cout &lt;&lt; "Base::g(float) " &lt;&lt; x &lt;&lt; endl; }<br />
void h(float x){ cout &lt;&lt; "Base::h(float) " &lt;&lt; x &lt;&lt; endl; }<br />
};<br />
class Derived : public Base<br />
{<br />
public:<br />
virtual void f(float x){ cout &lt;&lt; "Derived::f(float) " &lt;&lt; x &lt;&lt; endl; }<br />
void g(int x){ cout &lt;&lt; "Derived::g(int) " &lt;&lt; x &lt;&lt; endl; }<br />
void h(float x){ cout &lt;&lt; "Derived::h(float) " &lt;&lt; x &lt;&lt; endl; }<br />
};<br />
示例8-2-2（a）成员函数的重载、覆盖和隐藏<br />
据作者考察，很多C++程序员没有意识到有&#8220;隐藏&#8221;这回事。由于认识不够深刻，<br />
&#8220;隐藏&#8221;的发生可谓神出鬼没，常常产生令人迷惑的结果。<br />
示例8-2-2（b）中，bp 和dp 指向同一地址，按理说运行结果应该是相同的，可事<br />
实并非这样。</p>
<p>void main(void)<br />
{<br />
Derived d;<br />
Base *pb = &amp;d;<br />
Derived *pd = &amp;d;<br />
// Good : behavīor depends solely on type of the object<br />
pb-&gt;f(3.14f); // Derived::f(float) 3.14<br />
pd-&gt;f(3.14f); // Derived::f(float) 3.14<br />
// Bad : behavīor depends on type of the pointer<br />
pb-&gt;g(3.14f); // Base::g(float) 3.14<br />
pd-&gt;g(3.14f); // Derived::g(int) 3 (surprise!)<br />
// Bad : behavīor depends on type of the pointer<br />
pb-&gt;h(3.14f); // Base::h(float) 3.14 (surprise!)<br />
pd-&gt;h(3.14f); // Derived::h(float) 3.14<br />
}<br />
示例8-2-2（b） 重载、覆盖和隐藏的比较<br />
8.2.3 摆脱隐藏<br />
隐藏规则引起了不少麻烦。示例8-2-3 程序中，语句pd-&gt;f(10)的本意是想调用函<br />
数Base::f(int)，但是Base::f(int)不幸被Derived::f(char *)隐藏了。由于数字10<br />
不能被隐式地转化为字符串，所以在编译时出错。<br />
class Base<br />
{<br />
public:<br />
void f(int x);<br />
};<br />
class Derived : public Base<br />
{<br />
public:<br />
void f(char *str);<br />
};<br />
void Test(void)<br />
{<br />
Derived *pd = new Derived;<br />
pd-&gt;f(10); // error<br />
}<br />
示例8-2-3 由于隐藏而导致错误</p>
<p>从示例8-2-3 看来，隐藏规则似乎很愚蠢。但是隐藏规则至少有两个存在的理由：<br />
􀂋 写语句pd-&gt;f(10)的人可能真的想调用Derived::f(char *)函数，只是他误将参数<br />
写错了。有了隐藏规则，编译器就可以明确指出错误，这未必不是好事。否则，编<br />
译器会静悄悄地将错就错，程序员将很难发现这个错误，流下祸根。<br />
􀂋 假如类Derived 有多个基类（多重继承），有时搞不清楚哪些基类定义了函数f。如<br />
果没有隐藏规则，那么pd-&gt;f(10)可能会调用一个出乎意料的基类函数f。尽管隐<br />
藏规则看起来不怎么有道理，但它的确能消灭这些意外。<br />
示例8-2-3 中，如果语句pd-&gt;f(10)一定要调用函数Base::f(int)，那么将类<br />
Derived 修改为如下即可。<br />
class Derived : public Base<br />
{<br />
public:<br />
void f(char *str);<br />
void f(int x) { Base::f(x); }<br />
};</p>
<img src ="http://www.blogjava.net/tinysun/aggbug/305609.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-12-11 17:08 <a href="http://www.blogjava.net/tinysun/archive/2009/12/11/305609.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转-从一个C++笔试题看浮点数的表示</title><link>http://www.blogjava.net/tinysun/archive/2009/12/10/305435.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 10 Dec 2009 07:51:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/12/10/305435.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/305435.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/12/10/305435.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/305435.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/305435.html</trackback:ping><description><![CDATA[<table style="border-collapse: collapse; word-wrap: break-word" cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td align="center">
            <table style="border-collapse: collapse; word-wrap: break-word" cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td width="100%">
                        <div id="art" style="margin: 15px" width="100%">
                        <p style="margin: 0mm 0mm 10pt"><span style="font-size: small"><span style="font-family: 宋体">网上流行的一份</span><span style="font-family: 'Courier New'">C++</span><span style="font-family: 宋体">笔试题目中有这样一个题目（最初出处未知，从</span><span style="font-family: 'Courier New'">google</span><span style="font-family: 宋体">或者</span><span style="font-family: 'Courier New'">baidu</span><span style="font-family: 宋体">可搜索到多出来源）</span></span></p>
                        <p style="margin: 0mm 0mm 10pt"><span style="font-size: small"><span style="font-family: 'Courier New'">10. </span><span style="font-family: 宋体">以下两条输出语句分别输出什么？</span><span style="font-family: 'Courier New'">[C++</span><span style="font-family: 宋体">难</span></span><span style="font-size: small"><span style="font-family: 'Courier New'">]<br />
                        <span style="color: rgb(255,0,0)">float a = 1.0f;<br />
                        cout &lt;&lt; (int)a &lt;&lt; endl;<br />
                        cout &lt;&lt; (int&amp;)a &lt;&lt; endl;<br />
                        cout &lt;&lt; boolalpha &lt;&lt; ( (int)a == (int&amp;)a ) &lt;&lt; endl; // </span></span><span style="font-family: 宋体"><span style="color: rgb(255,0,0)">输出什么？</span></span></span><span style="font-family: 'Courier New'"><br />
                        <span style="color: rgb(255,0,0)">float b = 0.0f;<br />
                        cout &lt;&lt; (int)b &lt;&lt; endl;<br />
                        cout &lt;&lt; (int&amp;)b &lt;&lt; endl;<br />
                        cout &lt;&lt; boolalpha &lt;&lt; ( (int)b == (int&amp;)b ) &lt;&lt; endl; // </span></span><span style="font-size: small"><span style="color: rgb(255,0,0)"><span style="font-family: 宋体">输出什么？</span></span></span></p>
                        <p style="margin: 0mm 0mm 10pt"><span style="font-size: small"><span style="font-family: 宋体">这个题目涉及</span><span style="font-family: 'Courier New'">float</span><span style="font-family: 宋体">在计算机中的存储问题，</span><span style="font-family: 'Courier New'">IEEE 754</span><span style="font-family: 宋体">的标准就是描述的这个问题。如果这个题目放在笔试的时候应该比面试的时候容易多了。</span></span></p>
                        <p style="margin: 0mm 0mm 10pt"><span style="font-size: small"><span style="font-family: 宋体">这个题目的几个答案为</span><span style="font-family: 'Courier New'">1</span><span style="font-family: 宋体">，</span><span style="font-family: 'Courier New'">1065353216</span><span style="font-family: 宋体">（</span><span style="font-family: 'Courier New'">0x3f800000H</span><span style="font-family: 宋体">），</span><span style="font-family: 'Courier New'">false</span><span style="font-family: 宋体">，</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">，</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">，</span><span style="font-family: 'Courier New'">true</span><span style="font-family: 宋体">。如果你已完美的答出这六个答案，就可以忽略后面的内容。</span></span></p>
                        <h1 style="margin: 24pt 0mm 0pt"><span style="color: rgb(54,95,145)"><span style="font-family: Cambria">1.</span><span style="font-family: 宋体">我们先来看一下</span><span style="font-family: Cambria">IEEE 754</span><span style="font-family: 宋体">中关于</span><span style="font-family: Cambria">float</span><span style="font-family: 宋体">，</span><span style="font-family: Cambria">double</span><span style="font-family: 宋体">的存储规范。</span></span></h1>
                        <p style="background: white; margin: 0mm 0mm 10pt; text-indent: 24pt; line-height: normal; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="color: black; font-family: 宋体">无论是单精度还是双精度在存储中都分为三个部分：</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt 51pt; text-indent: -18pt; line-height: normal; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="color: black; font-family: 'Courier New'"><span style="font-size: small">1.&nbsp;</span></span><span style="font-size: small"><span style="color: black; font-family: 宋体">符号位</span><span style="color: black; font-family: 'Courier New'">(Sign) : 0</span><span style="color: black; font-family: 宋体">代表正，</span><span style="color: black; font-family: 'Courier New'">1</span><span style="color: black; font-family: 宋体">代表为负</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt 51pt; text-indent: -18pt; line-height: normal; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="color: black; font-family: 'Courier New'"><span style="font-size: small">2.&nbsp;</span></span><span style="font-size: small"><span style="color: black; font-family: 宋体">指数位（</span><span style="color: black; font-family: 'Courier New'">Exponent</span><span style="color: black; font-family: 宋体">）</span><span style="color: black; font-family: 'Courier New'">:</span><span style="color: black; font-family: 宋体">用于存储科学计数法中的指数数据，并且采用移位存储</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt 51pt; text-indent: -18pt; line-height: normal; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="color: black; font-family: 'Courier New'"><span style="font-size: small">3.&nbsp;</span></span><span style="font-size: small"><span style="color: black; font-family: 宋体">尾数部分（</span><span style="color: black; font-family: 'Courier New'">Mantissa</span><span style="color: black; font-family: 宋体">）：尾数部分</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt; text-indent: 24pt; line-height: normal; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="color: black; font-family: 宋体">其中</span><span style="color: black; font-family: 'Courier New'">float</span><span style="color: black; font-family: 宋体">的存储方式如下图所示：</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt; text-indent: 24pt; line-height: normal; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">&nbsp;<img height="150" alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/abortexit/EntryImages/20090622/1.JPG" width="477" /></p>
                        <p style="margin: 12pt 0mm 10pt; text-indent: 21.75pt"><span style="font-size: small"><span style="font-family: 宋体">指数部分（</span><span style="font-family: 'Courier New'">E</span><span style="font-family: 宋体">）　占用８</span><span style="font-family: 'Courier New'">-bit</span><span style="font-family: 宋体">的二进制数，可表示数值范围为</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">－</span><span style="font-family: 'Courier New'">255</span><span style="font-family: 宋体">。　但是指数应可正可负，所以</span><span style="font-family: 'Courier New'">IEEE</span><span style="font-family: 宋体">规定，此处算出的次方须减去</span><span style="font-family: 'Courier New'">127</span><span style="font-family: 宋体">才是真正的指数。所以</span><span style="font-family: 'Courier New'">float</span><span style="font-family: 宋体">的指数可从</span><span style="font-family: 'Courier New'"> -126</span><span style="font-family: 宋体">到</span><span style="font-family: 'Courier New'">128.</span></span></p>
                        <p style="margin: 12pt 0mm 10pt; text-indent: 21.75pt"><span style="font-size: small"><span style="font-family: 宋体">尾数部分（</span><span style="font-family: 'Courier New'">M</span><span style="font-family: 宋体">）实际是占用</span><span style="font-family: 'Courier New'">24-bit</span><span style="font-family: 宋体">的一个值，由于其最高位始终为</span><span style="font-family: 'Courier New'"> 1 </span><span style="font-family: 宋体">，所以最高位省去不存储，在存储中只有</span><span style="font-family: 'Courier New'">23-bit</span><span style="font-family: 宋体">。</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt; text-indent: 24pt; line-height: normal; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="font-family: 宋体">符号位：</span><span style="font-family: 'Courier New'">s </span><span style="font-family: 宋体">通过（</span><span style="font-family: 'Courier New'">-1</span><span style="font-family: 宋体">）的</span><span style="font-family: 'Courier New'">s</span><span style="font-family: 宋体">次幂来表示正负号。</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt; text-indent: 24pt; line-height: normal; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="color: black; font-family: 宋体">而双精度的存储方式为</span><span style="color: black; font-family: 'Courier New'">: <br />
                        </p>
                        <p style="margin: 0cm 0cm 0pt"><font face="宋体">double<span style="font-family: 宋体">：</span></font></p>
                        <p>
                        <table style="border-right: medium none; border-top: medium none; border-left: medium none; border-bottom: medium none; border-collapse: collapse" cellspacing="0" cellpadding="0" border="1">
                            <tbody>
                                <tr>
                                    <td style="border-right: windowtext 1pt solid; padding-right: 5.4pt; border-top: windowtext 1pt solid; padding-left: 5.4pt; padding-bottom: 0cm; border-left: windowtext 1pt solid; width: 142pt; padding-top: 0cm; border-bottom: windowtext 1pt solid; background-color: transparent" valign="top" width="189">
                                    <p style="margin: 0cm 0cm 0pt; text-indent: 0cm; text-align: center" align="center"><font face="宋体">1bit<span style="font-family: 宋体">（符号位）</span></font></p>
                                    </td>
                                    <td style="border-right: windowtext 1pt solid; padding-right: 5.4pt; border-top: windowtext 1pt solid; padding-left: 5.4pt; padding-bottom: 0cm; border-left: #ffffff; width: 142.05pt; padding-top: 0cm; border-bottom: windowtext 1pt solid; background-color: transparent" valign="top" width="189">
                                    <p style="margin: 0cm 0cm 0pt; text-indent: 0cm; text-align: center" align="center"><font face="宋体">11bits<span style="font-family: 宋体">（指数位）</span></font></p>
                                    </td>
                                    <td style="border-right: windowtext 1pt solid; padding-right: 5.4pt; border-top: windowtext 1pt solid; padding-left: 5.4pt; padding-bottom: 0cm; border-left: #ffffff; width: 142.05pt; padding-top: 0cm; border-bottom: windowtext 1pt solid; background-color: transparent" valign="top" width="189">
                                    <p style="margin: 0cm 0cm 0pt; text-indent: 0cm; text-align: center" align="center"><font face="宋体">52bits<span style="font-family: 宋体">（尾数位）</span></font></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </p>
                        <p style="background: white; margin: 0mm 0mm 10pt; text-indent: 24pt; line-height: normal; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><br />
                        </span></span></p>
                        <p style="background: white; margin: 0mm 0mm 7.5pt; line-height: 21.6pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="color: blue; font-family: 黑体">我们把</span><span style="color: blue; font-family: 'Courier New'">E</span><span style="color: blue; font-family: 黑体">，</span><span style="color: blue; font-family: 'Courier New'">M</span><span style="color: blue; font-family: 黑体">从二进制串表示转换为真正的</span><span style="color: blue; font-family: 'Courier New'">e</span><span style="color: blue; font-family: 黑体">、</span><span style="color: blue; font-family: 'Courier New'">m</span></span><span style="color: rgb(32,73,103); font-family: 'Courier New'"><br />
                        </span><span style="font-size: small"><span style="color: rgb(32,73,103); font-family: 黑体">这里要涉及到</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">&#8220;</span><span style="color: rgb(32,73,103); font-family: 黑体">规格化</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">(normalized)&#8221;</span><span style="color: rgb(32,73,103); font-family: 黑体">、</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">&#8220;</span><span style="color: rgb(32,73,103); font-family: 黑体">非规格化</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">(denormalized)&#8221;</span><span style="color: rgb(32,73,103); font-family: 黑体">。</span><span style="color: red; font-family: 黑体">规格化与否全看指数</span><span style="color: red; font-family: 'Courier New'">E</span><span style="color: red; font-family: 黑体">！</span><span style="color: rgb(32,73,103); font-family: 黑体">下面分三种情况讨论</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">E</span><span style="color: rgb(32,73,103); font-family: 黑体">，并分别计算</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">e</span><span style="color: rgb(32,73,103); font-family: 黑体">和</span></span><span style="font-size: small"><span style="color: rgb(32,73,103); font-family: 'Courier New'">m:<br />
                        </span><span style="color: red; font-family: 'Courier New'">1</span><span style="color: red; font-family: 黑体">、规格化：当</span><span style="color: red; font-family: 'Courier New'">E</span><span style="color: red; font-family: 黑体">的二进制位不全为</span><span style="color: red; font-family: 'Courier New'">0,</span><span style="color: red; font-family: 黑体">也不全为</span><span style="color: red; font-family: 'Courier New'">1</span><span style="color: red; font-family: 黑体">时，</span><span style="color: red; font-family: 'Courier New'">N</span><span style="color: red; font-family: 黑体">为规格化形式。</span><span style="color: rgb(32,73,103); font-family: 黑体">此时</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">e</span><span style="color: rgb(32,73,103); font-family: 黑体">被解释为表示偏置（</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">biased</span><span style="color: rgb(32,73,103); font-family: 黑体">）形式的整数</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">,e</span><span style="color: rgb(32,73,103); font-family: 黑体">值计算公式如下图所示：</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 7.5pt; line-height: 21.6pt; text-align: center; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" align="center"><img height="126" alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/abortexit/EntryImages/20090622/3.JPG" width="336" />&nbsp;</p>
                        <p style="background: white; margin: 7.5pt 0mm; line-height: 21.6pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="color: rgb(32,73,103); font-family: 黑体">上图中，</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">|E|</span><span style="color: rgb(32,73,103); font-family: 黑体">表示</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">E</span><span style="color: rgb(32,73,103); font-family: 黑体">的二进制序列表示的整数值</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">,</span><span style="color: rgb(32,73,103); font-family: 黑体">例如</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">E</span><span style="color: rgb(32,73,103); font-family: 黑体">为</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">"10000100",</span><span style="color: rgb(32,73,103); font-family: 黑体">则</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">|E|=132,e=132-127=5 </span><span style="color: rgb(32,73,103); font-family: 黑体">。</span><span style="color: rgb(32,73,103); font-family: 'Courier New'"> k</span><span style="color: rgb(32,73,103); font-family: 黑体">则表示</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">E</span><span style="color: rgb(32,73,103); font-family: 黑体">的位数，对单精度来说，</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">k=8,</span><span style="color: rgb(32,73,103); font-family: 黑体">则</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">bias=127</span><span style="color: rgb(32,73,103); font-family: 黑体">，对双精度来说，</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">k=11,</span><span style="color: rgb(32,73,103); font-family: 黑体">则</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">bias=1023</span><span style="color: rgb(32,73,103); font-family: 黑体">。</span></span></p>
                        <p style="background: white; margin: 7.5pt 0mm; line-height: 21.6pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="color: rgb(32,73,103); font-family: 黑体">此时</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">m</span><span style="color: rgb(32,73,103); font-family: 黑体">的计算公式如下图所示：</span></span><span style="color: rgb(32,73,103); font-family: 'Courier New'"><br />
                        <br />
                        </span></p>
                        <p style="background: white; margin: 0mm 0mm 7.5pt; line-height: 21.6pt; text-align: center; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" align="center"><img height="73" alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/abortexit/EntryImages/20090622/4.JPG" width="339" />&nbsp;</p>
                        <p style="background: white; margin: 7.5pt 0mm; line-height: 21.6pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="color: rgb(32,73,103); font-family: 黑体">标准规定此时小数点左侧的隐含位为</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">1,</span><span style="color: rgb(32,73,103); font-family: 黑体">那么</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">m=|1.M|</span><span style="color: rgb(32,73,103); font-family: 黑体">。如</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">M="101"</span><span style="color: rgb(32,73,103); font-family: 黑体">，则</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">|1.M|=|1.101|=1.625,</span><span style="color: rgb(32,73,103); font-family: 黑体">即</span></span><span style="font-size: small"><span style="color: rgb(32,73,103); font-family: 'Courier New'"> m=1.625<br />
                        <br />
                        </span><span style="color: red; font-family: 'Courier New'">2</span><span style="color: red; font-family: 黑体">、非规格化：当</span><span style="color: red; font-family: 'Courier New'">E</span><span style="color: red; font-family: 黑体">的二进制位全部为</span><span style="color: red; font-family: 'Courier New'">0</span><span style="color: red; font-family: 黑体">时，</span><span style="color: red; font-family: 'Courier New'">N</span><span style="color: red; font-family: 黑体">为非规格化形式。</span><span style="color: rgb(32,73,103); font-family: 黑体">此时</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">e</span><span style="color: rgb(32,73,103); font-family: 黑体">，</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">m</span><span style="color: rgb(32,73,103); font-family: 黑体">的计算都非常简单。</span></span></p>
                        <p style="background: white; margin: 7.5pt 0mm; line-height: 21.6pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="color: rgb(32,73,103); font-family: 'Courier New'"><img height="115" alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/abortexit/EntryImages/20090622/5.JPG" width="335" /><br />
                        </span></p>
                        <p style="background: white; margin: 7.5pt 0mm 10pt; line-height: 21.6pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="color: rgb(32,73,103); font-family: 黑体">注意，此时小数点左侧的隐含位为</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">0</span><span style="color: rgb(32,73,103); font-family: 黑体">。</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">&nbsp;&nbsp; </span><span style="color: rgb(32,73,103); font-family: 黑体">为什么</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">e</span><span style="color: rgb(32,73,103); font-family: 黑体">会等于</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">(1-bias)</span><span style="color: rgb(32,73,103); font-family: 黑体">而不是</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">(-bias)</span><span style="color: rgb(32,73,103); font-family: 黑体">，这主要是为规格化数值、非规格化数值之间的平滑过渡设计的。后文我们还会继续讨论。有了非规格化形式，我们就可以表示</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">0</span><span style="color: rgb(32,73,103); font-family: 黑体">了。把符号位</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">S</span><span style="color: rgb(32,73,103); font-family: 黑体">值</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">1,</span><span style="color: rgb(32,73,103); font-family: 黑体">其余所有位均置</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">0</span><span style="color: rgb(32,73,103); font-family: 黑体">后，我们得到了</span><span style="color: rgb(32,73,103); font-family: 'Courier New'"> -0.0; </span><span style="color: rgb(32,73,103); font-family: 黑体">同理，把所有位均置</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">0,</span><span style="color: rgb(32,73,103); font-family: 黑体">则得到</span><span style="color: rgb(32,73,103); font-family: 'Courier New'"> +0.0</span><span style="color: rgb(32,73,103); font-family: 黑体">。非规格化数还有</span><span style="color: rgb(32,73,103); font-family: 'Courier New'"><a href="javascript:;" target="_self"><strong><span style="color: rgb(0,0,102); font-family: 黑体">其他</span></strong></a></span><span style="color: rgb(32,73,103); font-family: 黑体">用途，比如表示非常接近</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">0</span><span style="color: rgb(32,73,103); font-family: 黑体">的小数，而且这些小数均匀地接近</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">0,</span><span style="color: rgb(32,73,103); font-family: 黑体">称为</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">&#8220;</span><span style="color: rgb(32,73,103); font-family: 黑体">逐渐下溢</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">(gradually underflow)&#8221;</span><span style="color: rgb(32,73,103); font-family: 黑体">属性。</span></span><span style="color: rgb(32,73,103); font-family: 'Courier New'"><br />
                        </span><span style="font-size: small"><span style="color: red; font-family: 'Courier New'">3</span><span style="color: red; font-family: 黑体">、特殊数值：当</span><span style="color: red; font-family: 'Courier New'">E</span><span style="color: red; font-family: 黑体">的二进制位全为</span><span style="color: red; font-family: 'Courier New'">1</span><span style="color: red; font-family: 黑体">时为特殊数值。</span><span style="color: rgb(32,73,103); font-family: 黑体">此时，若</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">M</span><span style="color: rgb(32,73,103); font-family: 黑体">的二进制位全为</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">0</span><span style="color: rgb(32,73,103); font-family: 黑体">，则</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">n</span><span style="color: rgb(32,73,103); font-family: 黑体">表示无穷大，若</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">S</span><span style="color: rgb(32,73,103); font-family: 黑体">为</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">1</span><span style="color: rgb(32,73,103); font-family: 黑体">则为负无穷大，若</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">S</span><span style="color: rgb(32,73,103); font-family: 黑体">为</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">0</span><span style="color: rgb(32,73,103); font-family: 黑体">则为正无穷大</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">; </span><span style="color: rgb(32,73,103); font-family: 黑体">若</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">M</span><span style="color: rgb(32,73,103); font-family: 黑体">的二进制位不全为</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">0</span><span style="color: rgb(32,73,103); font-family: 黑体">时，表示</span><span style="color: rgb(32,73,103); font-family: 'Courier New'">NaN(Not a Number)</span><span style="color: rgb(32,73,103); font-family: 黑体">，表示这不是一个合法实数或无穷，或者该数未经初始化。</span></span></p>
                        <h1 style="margin: 24pt 0mm 0pt"><span style="color: rgb(54,95,145)"><span style="font-family: Cambria">2.</span><span style="font-family: 宋体">问题的解答</span></span></h1>
                        <p style="margin: 0mm 0mm 10pt"><span style="font-size: small"><span style="font-family: 宋体">对于</span><span style="font-family: 'Courier New'">1.0f</span><span style="font-family: 宋体">这个数字，我们应该如何表示？按照上面的规则可以得到，符号位为</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">，指数位为</span><span style="font-family: 'Courier New'">127</span><span style="font-family: 宋体">（</span><span style="font-family: 'Courier New'">0x7F</span><span style="font-family: 宋体">），尾数部分</span><span style="font-family: 'Courier New'">M</span><span style="font-family: 宋体">应该为全</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">。因此它在计算机中的存储就是</span><span style="font-family: 'Courier New'">0x3F800000H</span><span style="font-family: 宋体">。</span></span></p>
                        <p style="margin: 0mm 0mm 10pt"><span style="font-family: 'Courier New'"><span style="font-size: small">cout &lt;&lt; (int)a &lt;&lt; endl;</span></span></p>
                        <p style="margin: 0mm 0mm 10pt"><span style="font-size: small"><span style="font-family: 宋体">把</span><span style="font-family: 'Courier New'">a</span><span style="font-family: 宋体">从浮点数转换为整数，由于</span><span style="font-family: 'Courier New'">1.0f</span><span style="font-family: 宋体">能够使用</span><span style="font-family: 'Courier New'">32bits</span><span style="font-family: 宋体">完整的表示，没有舍入误差，因此会输出整数</span></span><span style="font-family: 'Courier New'"><span style="font-size: small"> 1<br />
                        cout &lt;&lt; (int&amp;)a &lt;&lt; endl;</span></span></p>
                        <p style="margin: 0mm 0mm 10pt"><span style="font-size: small"><span style="font-family: 宋体">把</span><span style="font-family: 'Courier New'">a</span><span style="font-family: 宋体">里面的内容转换为整数地址，因此编译器会直接浮点数的</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位表示直接输出，，即</span><span style="font-family: 'Courier New'">0x3f800000h</span><span style="font-family: 宋体">的</span><span style="font-family: 'Courier New'">10</span><span style="font-family: 宋体">进制表示。</span></span></p>
                        <p style="margin: 0mm 0mm 10pt"><span style="font-size: small"><span style="font-family: 宋体">对于</span><span style="font-family: 'Courier New'">0.0f</span><span style="font-family: 宋体">这个特殊的表示上面已经提到了，它在内存中的存储就是全</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">，因此直接把浮点数转换为整数还是直接把浮点数的表示转化为整数地址结果都是</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">。</span></span></p>
                        <p style="margin: 0mm 0mm 10pt"><span style="font-size: small"><span style="font-family: 宋体">正如上面提到的一样，浮点数</span><span style="font-family: 'Courier New'">-0</span><span style="font-family: 宋体">的表示和</span><span style="font-family: 'Courier New'">+0</span><span style="font-family: 宋体">的表示是不同的，</span><span style="font-family: 'Courier New'">-0</span><span style="font-family: 宋体">在内存中的表示为</span><span style="font-family: 'Courier New'">0x80000000H</span><span style="font-family: 宋体">。</span></span></p>
                        <p style="margin: 0mm 0mm 10pt"><span style="font-size: small"><span style="font-family: 宋体">最后再转载一点关于</span><span style="font-family: 'Courier New'">long double</span><span style="font-family: 宋体">的知识，我也没有自己深入。</span></span></p>
                        <h1 style="margin: 24pt 0mm 0pt"><span style="color: rgb(54,95,145)"><span style="font-family: 'Courier New'">3.</span><span style="font-family: 宋体">扩展双精度格</span><span style="font-family: 宋体">式（</span><span style="font-family: 宋体">long double）</span></span></h1>
                        <p style="background: white; margin: 0mm 0mm 10pt; line-height: 16.5pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="font-family: 宋体">⑴</span><span style="font-family: 宋体">扩展双精度格式（</span><span style="font-family: 'Courier New'">SPARC </span><span style="font-family: 宋体">结构计算机）</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt; line-height: 16.5pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="font-family: 宋体">该</span><span style="font-family: 'Courier New'">4</span><span style="font-family: 宋体">倍精度浮点环境符合</span><span style="font-family: 'Courier New'">IEEE</span><span style="font-family: 宋体">关于扩展双精度格式的定义。该浮点环境的</span><span style="font-family: 'Courier New'">4</span><span style="font-family: 宋体">倍精度浮点格式共</span><span style="font-family: 'Courier New'">128</span><span style="font-family: 宋体">位，占</span><span style="font-family: 'Courier New'">4</span><span style="font-family: 宋体">个连续</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字，包含</span><span style="font-family: 'Courier New'">3</span><span style="font-family: 宋体">个构成字段：</span><span style="font-family: 'Courier New'">112</span><span style="font-family: 宋体">位的小数</span><span style="font-family: 'Courier New'">f</span><span style="font-family: 宋体">，</span><span style="font-family: 'Courier New'">15</span><span style="font-family: 宋体">位的偏置指数</span><span style="font-family: 'Courier New'">e</span><span style="font-family: 宋体">，和</span><span style="font-family: 'Courier New'">1</span><span style="font-family: 宋体">位的符号</span><span style="font-family: 'Courier New'">s</span><span style="font-family: 宋体">。将这</span><span style="font-family: 'Courier New'">4</span><span style="font-family: 宋体">个连续的</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字整体作为一个</span><span style="font-family: 'Courier New'">128</span><span style="font-family: 宋体">位的字，进行重新编号。其中</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">：</span><span style="font-family: 'Courier New'">110</span><span style="font-family: 宋体">位包含小数</span><span style="font-family: 'Courier New'">f</span><span style="font-family: 宋体">；</span><span style="font-family: 'Courier New'">112</span><span style="font-family: 宋体">：</span><span style="font-family: 'Courier New'">126</span><span style="font-family: 宋体">位包含偏置指数</span><span style="font-family: 'Courier New'">e</span><span style="font-family: 宋体">；第</span><span style="font-family: 'Courier New'">127</span><span style="font-family: 宋体">位包含符号位</span><span style="font-family: 'Courier New'">s</span><span style="font-family: 宋体">。如图</span><span style="font-family: 'Courier New'">3</span><span style="font-family: 宋体">所示</span><span style="font-family: 宋体">。</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt; line-height: 16.5pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="font-family: 宋体">在</span><span style="font-family: 'Courier New'">SPARC</span><span style="font-family: 宋体">结构计算机中，地址最高的</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字存放小数的</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位最低有效位，即</span><span style="font-family: 'Courier New'">f[31:0]</span><span style="font-family: 宋体">；但是在</span><span style="font-family: 'Courier New'">PowerPC</span><span style="font-family: 宋体">结构计算机中，却是地址最低的</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字存放这些位</span><span style="font-family: 宋体">。</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt; line-height: 16.5pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="font-family: 宋体">紧邻的两个</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字（在</span><span style="font-family: 'Courier New'">SPARC</span><span style="font-family: 宋体">机中向下计算，在</span><span style="font-family: 'Courier New'">PowerPC</span><span style="font-family: 宋体">机中向上计算）分别存放</span><span style="font-family: 'Courier New'">f[63:32]</span><span style="font-family: 宋体">和</span><span style="font-family: 'Courier New'">f[95:64]</span><span style="font-family: 宋体">。</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt; line-height: 16.5pt; text-align: center; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" align="center"><span style="font-size: small"><span style="font-family: 宋体">最后一个字的第</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">到</span><span style="font-family: 'Courier New'">15</span><span style="font-family: 宋体">位存放小数的最高</span><span style="font-family: 'Courier New'">16</span><span style="font-family: 宋体">位</span><span style="font-family: 'Courier New'">,</span><span style="font-family: 宋体">即</span><span style="font-family: 'Courier New'">f[111:96]</span><span style="font-family: 宋体">。其中第</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">位存放该</span><span style="font-family: 'Courier New'">16</span><span style="font-family: 宋体">位的最低有效位，第</span><span style="font-family: 'Courier New'">15</span><span style="font-family: 宋体">位存放整个小数</span><span style="font-family: 'Courier New'">f</span><span style="font-family: 宋体">的最高有效位。第</span><span style="font-family: 'Courier New'">16</span><span style="font-family: 宋体">到</span><span style="font-family: 'Courier New'">30</span><span style="font-family: 宋体">位存放</span><span style="font-family: 'Courier New'">15</span><span style="font-family: 宋体">位的偏置指数</span><span style="font-family: 'Courier New'">e</span><span style="font-family: 宋体">，其中第</span><span style="font-family: 'Courier New'">16</span><span style="font-family: 宋体">位存放偏置指数的最低有效位，第</span><span style="font-family: 'Courier New'">30</span><span style="font-family: 宋体">位存放它的最高有效位。最高位，第</span><span style="font-family: 'Courier New'">31</span><span style="font-family: 宋体">位存放符号</span><span style="font-family: 'Courier New'">s</span><span style="font-family: 宋体">。</span></span><span style="font-family: 'Courier New'"><br />
                        </span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt; line-height: 16.5pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="font-family: 宋体">⑵</span><span style="font-family: 宋体">扩展双精度格式（</span><span style="font-family: 'Courier New'">Intel x86</span><span style="font-family: 宋体">结构计算机）</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt; line-height: 16.5pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="font-family: 宋体">该浮点环境双精度扩展格式符合</span><span style="font-family: 'Courier New'">IEEE</span><span style="font-family: 宋体">双精度扩展格式的定义。该浮点环境的扩展双精度格式共</span><span style="font-family: 'Courier New'">80</span><span style="font-family: 宋体">位，占</span><span style="font-family: 'Courier New'">3</span><span style="font-family: 宋体">个连续</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字，包含四个构成字段：</span><span style="font-family: 'Courier New'">63</span><span style="font-family: 宋体">位的小数</span><span style="font-family: 'Courier New'">f</span><span style="font-family: 宋体">，</span><span style="font-family: 'Courier New'">1</span><span style="font-family: 宋体">位显式前导有效位（</span><span style="font-family: 'Courier New'">explicit leading significand bit</span><span style="font-family: 宋体">）</span><span style="font-family: 'Courier New'">j</span><span style="font-family: 宋体">，</span><span style="font-family: 'Courier New'">15</span><span style="font-family: 宋体">位偏置指数</span><span style="font-family: 'Courier New'">e</span><span style="font-family: 宋体">，和</span><span style="font-family: 'Courier New'">1</span><span style="font-family: 宋体">位符号位</span><span style="font-family: 'Courier New'">s</span><span style="font-family: 宋体">。将这</span><span style="font-family: 'Courier New'">3</span><span style="font-family: 宋体">个连续的</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字整体作为一个</span><span style="font-family: 'Courier New'">96</span><span style="font-family: 宋体">位的字，进行重新编号。其中</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">：</span><span style="font-family: 'Courier New'">63</span><span style="font-family: 宋体">包含</span><span style="font-family: 'Courier New'">63</span><span style="font-family: 宋体">位的小数</span><span style="font-family: 'Courier New'">f</span><span style="font-family: 宋体">，第</span><span style="font-family: 'Courier New'">63</span><span style="font-family: 宋体">位包含前导有效位</span><span style="font-family: 'Courier New'">j</span><span style="font-family: 宋体">，</span><span style="font-family: 'Courier New'">64</span><span style="font-family: 宋体">：</span><span style="font-family: 'Courier New'">78</span><span style="font-family: 宋体">位包含</span><span style="font-family: 'Courier New'">15</span><span style="font-family: 宋体">位的偏置指数</span><span style="font-family: 'Courier New'">e</span><span style="font-family: 宋体">，最高位第</span><span style="font-family: 'Courier New'">79</span><span style="font-family: 宋体">位包含符号位</span><span style="font-family: 'Courier New'">s</span><span style="font-family: 宋体">。</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt; line-height: 16.5pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="font-family: 宋体">在</span><span style="font-family: 'Courier New'">Intel</span><span style="font-family: 宋体">结构系计算机中，这些字段依次存放在十个连续的字节中。但是，由于</span><span style="font-family: 'Courier New'"> UNIX&nbsp; System V Application Binary Interface Intel 386 Processor Supplement (Intel ABI) </span><span style="font-family: 宋体">要求双精度扩展参数，从而占用堆栈中</span><span style="font-family: 'Courier New'">3</span><span style="font-family: 宋体">个相连地址的</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字，其中最高一个字的高</span><span style="font-family: 'Courier New'">16</span><span style="font-family: 宋体">位未被使用</span><span style="font-family: 宋体">。</span></span></p>
                        <span style="font-size: small"><span style="font-family: 宋体">地址最低的</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字存放小数</span><span style="font-family: 'Courier New'">f</span><span style="font-family: 宋体">的低</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位，即</span><span style="font-family: 'Courier New'">f[31:0]</span><span style="font-family: 宋体">。其中第</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">位存放整个小数</span><span style="font-family: 'Courier New'">f</span><span style="font-family: 宋体">的最低有效位</span><span style="font-family: 'Courier New'">LSB </span><span style="font-family: 宋体">第</span><span style="font-family: 'Courier New'">31</span><span style="font-family: 宋体">位存放小数低</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位的最高有效位</span><span style="font-family: 'Courier New'">MSB</span><span style="font-family: 宋体">。</span></span>
                        <p style="background: white; margin: 0mm 0mm 10pt; line-height: 16.5pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="font-family: 宋体">地址居中的</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字，第</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">到</span><span style="font-family: 'Courier New'">30</span><span style="font-family: 宋体">位存放小数</span><span style="font-family: 'Courier New'">f</span><span style="font-family: 宋体">的</span><span style="font-family: 'Courier New'">31</span><span style="font-family: 宋体">位最高位，即</span><span style="font-family: 'Courier New'">f[62:32]</span><span style="font-family: 宋体">。其中第</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">位存放</span><span style="font-family: 'Courier New'">31</span><span style="font-family: 宋体">位最高小数位的最低有效位</span><span style="font-family: 'Courier New'">LSB</span><span style="font-family: 宋体">，第</span><span style="font-family: 'Courier New'">30</span><span style="font-family: 宋体">位存放整个小数的最高有效位，地址居中的</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字的最高位第</span><span style="font-family: 'Courier New'">31</span><span style="font-family: 宋体">位存放显式的前导有效位</span><span style="font-family: 'Courier New'">j</span><span style="font-family: 宋体">。</span></span></p>
                        <p style="background: white; margin: 0mm 0mm 10pt; line-height: 16.5pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"><span style="font-size: small"><span style="font-family: 宋体">地址最高</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字里，第</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">到</span><span style="font-family: 'Courier New'">14</span><span style="font-family: 宋体">位存放</span><span style="font-family: 'Courier New'">15</span><span style="font-family: 宋体">位的偏置指数</span><span style="font-family: 'Courier New'">e</span><span style="font-family: 宋体">，第</span><span style="font-family: 'Courier New'">0</span><span style="font-family: 宋体">位存放偏置指数的最低有效位</span><span style="font-family: 'Courier New'">LSB</span><span style="font-family: 宋体">，第</span><span style="font-family: 'Courier New'">14</span><span style="font-family: 宋体">位存放最高有效位</span><span style="font-family: 'Courier New'">MSB</span><span style="font-family: 宋体">，第</span><span style="font-family: 'Courier New'">15</span><span style="font-family: 宋体">位存放符号位</span><span style="font-family: 'Courier New'">s</span><span style="font-family: 宋体">。虽然地址最高的</span><span style="font-family: 'Courier New'">32</span><span style="font-family: 宋体">位字的高</span><span style="font-family: 'Courier New'">16</span><span style="font-family: 宋体">位在</span><span style="font-family: 'Courier New'">Intel x86</span><span style="font-family: 宋体">结构系列机种未被使用，但他们对符合</span><span style="font-family: 'Courier New'">Intel ABI</span><span style="font-family: 宋体">的规定来说，是必需的</span><span style="font-family: 宋体">。</span></span></p>
                        </div>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
        <tr>
            <td height="25">&nbsp;<font color="#000099"><strong>原文地址</strong></font> <a href="http://blog.csdn.net/abortexit/archive/2009/06/22/4288279.aspx" target="_blank">http://blog.csdn.net/abortexit/archive/2009/06/22/4288279.aspx</a> </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/tinysun/aggbug/305435.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-12-10 15:51 <a href="http://www.blogjava.net/tinysun/archive/2009/12/10/305435.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转-复制概念相关，深拷贝与浅拷贝</title><link>http://www.blogjava.net/tinysun/archive/2009/12/10/305432.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 10 Dec 2009 07:44:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/12/10/305432.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/305432.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/12/10/305432.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/305432.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/305432.html</trackback:ping><description><![CDATA[<table style="border-collapse: collapse; word-wrap: break-word" cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td align="center">
            <table style="border-collapse: collapse; word-wrap: break-word" cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td width="100%">
                        <div id="art" style="margin: 15px" width="100%">
                        <div class="" style="margin-top: 10px; font-weight: bold; margin-left: 10px; color: rgb(255,102,0); font-family: Arial,Helvetica,Sans-Serif">http://www.devx.com/tips/Tip/13625<br />
                        <br />
                        Deep Copy and Shallow Copy</div>
                        <div class="" style="padding-right: 10px; padding-left: 10px; padding-bottom: 10px; padding-top: 10px">The terms "deep copy" and "shallow copy" refer to the way objects are copied, for example, during the invocation of a copy constructor or assignment operator. In a deep copy (also called "memberwise copy"), the copy operation respects object semantics. For example, copying an object that has a member of type std::string ensures that the corresponding std::string in the target object is copy-constructed by the copy constructor of class std::string.
                        <pre><code> <br />
                        class A<br />
                        {<br />
                        string s;<br />
                        };<br />
                        A a;<br />
                        A b;<br />
                        a=b; //deep copy<br />
                        </code></pre>
                        <p>When assigning b to a, the compiler-generated assignment operator of class A first invokes the assignment operator of class std::string. Thus, a.s and b.s are well-defined, and they are probably not binary-identical. On the other hand, a shallow copy (also called "bitwise copy") simply copies chunks of memory from one location to another. A memcpy() operation is an example of a shallow copy. Because memcpy() does not respect object semantics, it will not invoke the copy constructor of an object. Therefore, you should never use memcpy() to copy objects. Use it only when copying POD (Plain Old Data) types: ints, floating point numbers, and dumb structs. <br />
                        </p>
                        <p>--------------------------------------------------------------------</p>
                        <p>http://www.uow.edu.au/~lukes/TEXTBOOK/notes-cpp/oop-condestructors/shallowdeepcopy.html<br />
                        </p>
                        <p>A <em style="color: rgb(0,1,255)">shallow copy</em> of an object copies all of the member field values. This works well if the fields are values, but may not be what you want for fields that point to dynamically allocated memory. The pointer will be copied. but the memory it points to will not be copied -- the field in both the original object and the copy will then point to the same dynamically allocated memory, which is not usually what you want. The default copy constructor and assignment operator make shallow copies. </p>
                        <p>A <em style="color: rgb(0,1,255)">deep copy</em> copies all fields, <em>and</em> makes copies of dynamically allocated memory pointed to by the fields. To make a deep copy, you must write a copy constructor and overload the assignment operator, otherwise the copy will point to the original, with disasterous consequences. </p>
                        </div>
                        </div>
                        </td>
                    </tr>
                </tbody>
            </table>
            <p style="margin: 5px; line-height: 150%"></p>
            </td>
        </tr>
        <tr>
            <td height="25">&nbsp;<font color="#000099"><strong>原文地址</strong></font> <a href="http://www.uow.edu.au/~lukes/TEXTBOOK/notes-cpp/oop-condestructors/shallowdeepcopy.html" target="_blank">http://www.uow.edu.au/~lukes/TEXTBOOK/notes-cpp/oop-condestructors/shallowdeepcopy.html</a> </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/tinysun/aggbug/305432.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-12-10 15:44 <a href="http://www.blogjava.net/tinysun/archive/2009/12/10/305432.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>chapter.2 Semantics of Constructors 构造函数语义 part2考构</title><link>http://www.blogjava.net/tinysun/archive/2009/12/10/305431.html</link><dc:creator>何克勤</dc:creator><author>何克勤</author><pubDate>Thu, 10 Dec 2009 07:35:00 GMT</pubDate><guid>http://www.blogjava.net/tinysun/archive/2009/12/10/305431.html</guid><wfw:comment>http://www.blogjava.net/tinysun/comments/305431.html</wfw:comment><comments>http://www.blogjava.net/tinysun/archive/2009/12/10/305431.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tinysun/comments/commentRss/305431.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tinysun/services/trackbacks/305431.html</trackback:ping><description><![CDATA[<div id="art" style="margin: 15px" width="100%">一 default memberwise initialization<br />
&nbsp;&nbsp; 通常我们都会为非抽象类定义拷贝构造函数，如果没有定义时，我们以class的一个object作为另一个object的初值时，编译器内部以default memberwise initialization 方式完成，对于member class object 则不会拷贝，而是递归调用 memberwise initialization。<br />
&nbsp;&nbsp; copy constructor和default constructor一样，在必要的时候才由编译器产生出来。copy constructor 以初始化的方式复制object，另一种是指定值（assignment），通过copy assignment operator<br />
<br />
二 bitwise copy semantics<br />
&nbsp;&nbsp; 编译器是否合成出考构是看class是否展现了 bitwise copy semantics，
<table style="border-collapse: collapse" bordercolor="#999999" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" border="1">
    <tbody>
        <tr>
            <td>
            <p style="margin: 5px; line-height: 150%"><code><span style="color: rgb(0,0,0)"><span style="color: rgb(255,153,0)">// <span style="color: rgb(255,1,2)">declaration exhibits bitwise copy semantics </span><br />
            </span><span style="color: rgb(0,0,255)">class</span> Word <span style="color: rgb(0,0,204)">{</span> <br />
            <span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,204)">:</span> <br />
            &nbsp;&nbsp;&nbsp;Word<span style="color: rgb(0,0,204)">(</span> <span style="color: rgb(0,0,255)">const</span> <span style="color: rgb(0,0,255)">char</span><span style="color: rgb(0,0,204)">*</span> <span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">;</span> <br />
            &nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,204)">~</span>Word<span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,204)">)</span> <span style="color: rgb(0,0,204)">{</span> <span style="color: rgb(0,0,255)">delete</span> <span style="color: rgb(0,0,204)">[</span><span style="color: rgb(0,0,204)">]</span> str<span style="color: rgb(0,0,204)">;</span> <span style="color: rgb(0,0,204)">}</span> <br />
            &nbsp;&nbsp;&nbsp;<span style="color: rgb(255,153,0)">// ... <br />
            </span><span style="color: rgb(0,0,255)">private</span><span style="color: rgb(0,0,204)">:</span> <br />
            &nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">int</span> cnt<span style="color: rgb(0,0,204)">;</span> <br />
            &nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">char</span> <span style="color: rgb(0,0,204)">*</span>str<span style="color: rgb(0,0,204)">;</span> <br />
            <span style="color: rgb(0,0,204)">}</span><span style="color: rgb(0,0,204)">;</span> </span></code></p>
            </td>
        </tr>
    </tbody>
</table>
如书中所说，这个展现了bitwise copy semantics，<span style="color: rgb(255,1,2)">why？<br />
<br />
</span>
<table style="border-collapse: collapse" bordercolor="#999999" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" border="1">
    <tbody>
        <tr>
            <td>
            <p style="margin: 5px; line-height: 150%"><code><span style="color: rgb(0,0,0)"><span style="color: rgb(255,153,0)">// declaration does <span style="color: rgb(255,1,2)">not</span> exhibits bitwise copy semantics <br />
            </span><span style="color: rgb(0,0,255)">class</span> Word <span style="color: rgb(0,0,204)">{</span> <br />
            <span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,204)">:</span> <br />
            &nbsp;&nbsp;&nbsp;Word<span style="color: rgb(0,0,204)">(</span> <span style="color: rgb(0,0,255)">const</span> <span style="color: rgb(255,0,0)">String</span><span style="color: rgb(0,0,204)">&amp;</span> <span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">;</span> <br />
            &nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,204)">~</span>Word<span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">;</span> <br />
            &nbsp;&nbsp;&nbsp;<span style="color: rgb(255,153,0)">// ... <br />
            </span><span style="color: rgb(0,0,255)">private</span><span style="color: rgb(0,0,204)">:</span> <br />
            &nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">int</span> cnt<span style="color: rgb(0,0,204)">;</span> <br />
            &nbsp;&nbsp;&nbsp;<span style="color: rgb(255,0,0)">String</span> str<span style="color: rgb(0,0,204)">;</span> <br />
            <span style="color: rgb(0,0,204)">}</span><span style="color: rgb(0,0,204)">;</span> </span></code></p>
            </td>
        </tr>
    </tbody>
</table>
这个没有展现，同样不明白。。。。。。。<br />
对于后者，编译器就会合成出一个 copy constructor。<br />
<br />
那么什么时候不展现bitwise copy semantics呢，分为四种情况<br />
（1）class 内含一个member object ，后者声明有一个copy constructor，无论是程序员声明的，还是被编译器合成的。<br />
（2）class 继承自的基类有一个copy constructor，无论程序员声明的，还是被编译器合成的。<br />
&nbsp;&nbsp; 对于这2种情况，编译器必须将memb或base class的copy constru调用操作安插到被合成的copy constr中。<br />
（3）class声明了一个或多个 virtual function时<br />
（4）class派生的基类串中至少有一个virtual base class时。<br />
<br />
&nbsp;&nbsp; 情况3中，类中会额外增加vptr和vbtl，故就不在展现bitwise seamantics了，编译器需要合成出一个copy constructor，以将vptr适当初始化。<br />
&nbsp;&nbsp; 同类型的对象vptr指向的相同的vtbl，基类和派生类的不同，看一段程序<br />
<br />
<table style="border-collapse: collapse" bordercolor="#999999" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" border="1">
    <tbody>
        <tr>
            <td>
            <p style="margin: 5px; line-height: 150%"><code><span style="color: rgb(0,0,0)"><span style="color: rgb(0,0,255)">class</span> b<span style="color: rgb(0,0,204)">{</span><br />
            <span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,204)">:</span><br />
            &nbsp;&nbsp;&nbsp; <span style="color: rgb(0,0,255)">int</span> i<span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">virtual</span> <span style="color: rgb(0,0,255)">void</span> f<span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">{</span><span style="color: rgb(0,0,204)">}</span><br />
            <span style="color: rgb(0,0,204)">}</span><span style="color: rgb(0,0,204)">;</span><br />
            <span style="color: rgb(0,0,255)">class</span> d<span style="color: rgb(0,0,204)">:</span><span style="color: rgb(0,0,255)">public</span> b<span style="color: rgb(0,0,204)">{</span><br />
            <span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,204)">:</span><br />
            &nbsp;&nbsp;&nbsp; <span style="color: rgb(0,0,255)">int</span> ii<span style="color: rgb(0,0,204)">;</span><br />
            <span style="color: rgb(0,0,204)">}</span><span style="color: rgb(0,0,204)">;</span><br />
            <br />
            <span style="color: rgb(0,0,255)">int</span> main<span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,255)">void</span><span style="color: rgb(0,0,204)">)</span> <span style="color: rgb(0,0,204)">{</span><br />
            &nbsp;&nbsp;&nbsp; b bbb<span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;d dob<span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;d bob<span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255,0,0)">cout</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&amp;</span>bbb<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,255)">" "</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&amp;</span>bbb<span style="color: rgb(0,0,204)">.</span>i<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,255)">" "</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,0)">endl</span><span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255,0,0)">cout</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&amp;</span>dob<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,255)">" "</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&amp;</span>dob<span style="color: rgb(0,0,204)">.</span>i<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,255)">" "</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&amp;</span>dob<span style="color: rgb(0,0,204)">.</span>ii<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,0)">endl</span><span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255,0,0)">cout</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&amp;</span>bob<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,255)">" "</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&amp;</span>bob<span style="color: rgb(0,0,204)">.</span>i<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,255)">" "</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&amp;</span>bob<span style="color: rgb(0,0,204)">.</span>ii<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,0)">endl</span><span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">int</span> <span style="color: rgb(0,0,204)">*</span>p<span style="color: rgb(0,0,204)">=</span><span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,255)">int</span> <span style="color: rgb(0,0,204)">*</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">&amp;</span>bbb<span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">int</span> <span style="color: rgb(0,0,204)">*</span>p2<span style="color: rgb(0,0,204)">=</span><span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,255)">int</span> <span style="color: rgb(0,0,204)">*</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">&amp;</span>dob<span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">int</span> <span style="color: rgb(0,0,204)">*</span>p3<span style="color: rgb(0,0,204)">=</span><span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,255)">int</span> <span style="color: rgb(0,0,204)">*</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">&amp;</span>bob<span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255,0,0)">cout</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,255)">"bbb vptr -&gt;"</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">*</span>p<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,0)">endl</span><span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255,0,0)">cout</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,255)">"dob vptr -&gt;"</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">*</span>p2<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,0)">endl</span><span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255,0,0)">cout</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,255)">"bob vptr -&gt;"</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">*</span>p3<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,0)">endl</span><span style="color: rgb(0,0,204)">;</span><br />
            <br />
            &nbsp;&nbsp;&nbsp;&nbsp;b bb2<span style="color: rgb(0,0,204)">=</span>dob<span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255,0,0)">cout</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&amp;</span>bb2<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,255)">" "</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&amp;</span>bb2<span style="color: rgb(0,0,204)">.</span>i<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,255)">" "</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,0)">endl</span><span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">int</span> <span style="color: rgb(0,0,204)">*</span>p4<span style="color: rgb(0,0,204)">=</span><span style="color: rgb(0,0,204)">(</span><span style="color: rgb(0,0,255)">int</span> <span style="color: rgb(0,0,204)">*</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">&amp;</span>bb2<span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(255,0,0)">cout</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,255)">"bb2 vptr -&gt;"</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">*</span>p4<span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(0,0,204)">&lt;</span><span style="color: rgb(255,0,0)">endl</span><span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp; <span style="color: rgb(255,0,0)">puts</span><span style="color: rgb(0,0,204)">(</span><span style="color: rgb(255,0,255)">"end in main"</span><span style="color: rgb(0,0,204)">)</span><span style="color: rgb(0,0,204)">;</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(0,0,255)">return</span> <span style="color: rgb(255,0,0)">EXIT_SUCCESS</span><span style="color: rgb(0,0,204)">;</span><br />
            <span style="color: rgb(0,0,204)">}</span><br />
            </span></code></p>
            </td>
        </tr>
    </tbody>
</table>
输出：<br />
<br />
<table style="border-collapse: collapse" bordercolor="#999999" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" border="1">
    <tbody>
        <tr>
            <td>
            <p style="margin: 5px; line-height: 150%"><code><span style="color: rgb(0,0,0)">0x22ff78 0x22ff7c <br />
            0x22ff68 0x22ff6c 0x22ff70<br />
            0x22ff58 0x22ff5c 0x22ff60<br />
            bbb vptr <span style="color: rgb(0,0,204)">-</span><span style="color: rgb(0,0,204)">&gt;</span>4409528<br />
            dob vptr <span style="color: rgb(0,0,204)">-</span><span style="color: rgb(0,0,204)">&gt;</span>4409544<br />
            bob vptr <span style="color: rgb(0,0,204)">-</span><span style="color: rgb(0,0,204)">&gt;</span>4409544<br />
            12 12<br />
            0x22ff48 0x22ff4c <br />
            bb2 vptr <span style="color: rgb(0,0,204)">-</span><span style="color: rgb(0,0,204)">&gt;</span>4409528<br />
            end in main<br />
            </span></code></p>
            </td>
        </tr>
    </tbody>
</table>
在 <code><span style="color: rgb(0,0,0)">b bb2<span style="color: rgb(0,0,204)">=</span>dob<span style="color: rgb(0,0,204)">; <span style="color: rgb(0,1,2)">语句处，发生了派生类对象的切割，其vptr指向了基类的vbtl，而不是派生类。<br />
<br />
参考文章： </span></span></span></code><a href="http://blog.chinaunix.net/u2/72955/showart.php?id=2058722" target="_blank"><font color="#006699">转-复制概念相关，深拷贝与浅拷贝</font></a> </div>
<img src ="http://www.blogjava.net/tinysun/aggbug/305431.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tinysun/" target="_blank">何克勤</a> 2009-12-10 15:35 <a href="http://www.blogjava.net/tinysun/archive/2009/12/10/305431.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>