﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-洗尘斋-随笔分类-C/C++</title><link>http://www.cppblog.com/lmlf001/category/1496.html</link><description>三悬明镜垂鸿韵，九撩清泉洗尘心
</description><language>zh-cn</language><lastBuildDate>Tue, 20 May 2008 23:40:58 GMT</lastBuildDate><pubDate>Tue, 20 May 2008 23:40:58 GMT</pubDate><ttl>60</ttl><item><title>标准输入输出的问题</title><link>http://www.cppblog.com/lmlf001/archive/2007/10/17/34471.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 17 Oct 2007 11:06:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2007/10/17/34471.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/34471.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2007/10/17/34471.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/34471.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/34471.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 先看下面一个小程序：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">int</span><span style="color: #000000;"> main(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;argc,&nbsp;_TCHAR</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FILE&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">fp</span><span style="color: #000000;">=</span><span style="color: #000000;">fopen(</span><span style="color: #000000;">"</span><span style="color: #000000;">1.txt</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">r+</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br></span><span style="color: #000000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fputc(</span><span style="color: #000000;">'</span><span style="color: #000000;">x</span><span style="color: #000000;">'</span><span style="color: #000000;">,fp);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fputc(</span><span style="color: #000000;">'</span><span style="color: #000000;">x</span><span style="color: #000000;">'</span><span style="color: #000000;">,fp);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fputc(</span><span style="color: #000000;">'</span><span style="color: #000000;">x</span><span style="color: #000000;">'</span><span style="color: #000000;">,fp);<br>&nbsp;&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></div>
&nbsp;&nbsp;&nbsp; 1.txt文件内容为abcdefg，调用函数之后为axxxefg，恩，正确<br><br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">int</span><span style="color: #000000;"> main(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;argc,&nbsp;_TCHAR</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FILE&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">fp</span><span style="color: #000000;">=</span><span style="color: #000000;">fopen(</span><span style="color: #000000;">"</span><span style="color: #000000;">1.txt</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">rb+</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;c</span><span style="color: #000000;">=</span><span style="color: #000000;">fgetc(fp);<br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fputc(</span><span style="color: #000000;">'</span><span style="color: #000000;">x</span><span style="color: #000000;">'</span><span style="color: #000000;">,fp);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fputc(</span><span style="color: #000000;">'</span><span style="color: #000000;">x</span><span style="color: #000000;">'</span><span style="color: #000000;">,fp);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fputc(</span><span style="color: #000000;">'</span><span style="color: #000000;">x</span><span style="color: #000000;">'</span><span style="color: #000000;">,fp);<br>&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp; return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}</span></div>
&nbsp;&nbsp;&nbsp; 而上面的这个程序只是加了一句fgetc，调用后却失去了作用，文件内容没有发生变化，仍然为abcdefg，为什么呢？（该问题在Linux下已不存在）<br>&nbsp;&nbsp;&nbsp; 《Unix环境高级编程》在使用读写方式打开文件时（type中的+号），输出的后面不能直接跟输入，输入的后面也不能直接跟输出，否则可能会出错。如果需要输出输入相连，则中间
需调用fflush,fseek,fsetpos或rewind等操作。<br>&nbsp;&nbsp;&nbsp; 既然这样，那我们试一下，看看能不能解决问题，在上面代码中fgetc和fputc中间加入<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fpos_t&nbsp;pos;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fgetpos(fp,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">pos);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fsetpos(fp,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">pos);</span></div>
之后，运行程序，果真可以解决问题。<br>&nbsp;&nbsp;&nbsp; C语言的标准I/O库函数由于使用缓存的原因，在使用时可能出现各种各样的问题，尤其是在那种即时性比较强的I/O中，使用时要慎重。尽量使用其他的I/O函数代替之。<br><br><br><br><img src ="http://www.cppblog.com/lmlf001/aggbug/34471.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2007-10-17 19:06 <a href="http://www.cppblog.com/lmlf001/archive/2007/10/17/34471.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>scanf的烦恼</title><link>http://www.cppblog.com/lmlf001/archive/2007/10/10/33913.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 10 Oct 2007 10:23:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2007/10/10/33913.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/33913.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2007/10/10/33913.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/33913.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/33913.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 今天连着2次用错scanf函数，这大概也是历史上第N+1次错误了，一直使用cin来输入数据，近来使用scanf的时候老出错误，因为它要去参数为一个地址，而编译器对于整数和地址的处理是类似的，往往不能指出错误。而当它运行时是不发生错误的，但会得到不正确的结果。。一步步的检查，并不能发现错误，只好打log，替换掉相应的块，然后逐步恢复原来的编码，最后才发现是sscanf的使用错误。这种错误实际上是有征兆的，因为程序每次运行时后使用的都是一个随机数据，而不是你所输入的数据。但编译的时候并不能发现错误。和往常的错误一样，编写一个程序可能只要半小时几分钟，而查找一个错误却花了我好几个小时的时间。这是一个不小的教训，也提示我在编译的时候-Wall选项的必要性。为了使我以后不会忘记使用这个选项，alias一下它吧，打开.profile文件，加入一行
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">alias&nbsp;gcc</span><span style="color: #000000;">=</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">gcc&nbsp;-Wall</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;"><br>alias&nbsp;g</span><span style="color: #000000;">++=</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">g++&nbsp;-Wall</span><span style="color: #000000; font-weight: bold;">'</span></div>
这样以后每次使用gcc/g++的时候它就自动启用-Wall选项了<br><img src ="http://www.cppblog.com/lmlf001/aggbug/33913.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2007-10-10 18:23 <a href="http://www.cppblog.com/lmlf001/archive/2007/10/10/33913.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>类成员函数的默认参数表问题</title><link>http://www.cppblog.com/lmlf001/archive/2007/09/08/31855.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Sat, 08 Sep 2007 12:58:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2007/09/08/31855.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/31855.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2007/09/08/31855.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/31855.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/31855.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 今天写程序的时候用到了函数的默认参数表，编译的时候老是无法通过，后来经过几次修改测试才发现是把类的函数参数表在函数定义时搞错了。<br>&nbsp;&nbsp;&nbsp; 类的成员函数的参数表在声明时默认参数位于参数表右部，若int fn(int a,int b=0,int c=5);之类的，但在它定义的时候则不能加默认参数，只能写int fn(int a,int b,int c);<br><br><a title="http://lmlf001.blog.sohu.com/"  href="http://lmlf001.blog.sohu.com/">http://lmlf001.blog.sohu.com/</a><br><img src ="http://www.cppblog.com/lmlf001/aggbug/31855.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2007-09-08 20:58 <a href="http://www.cppblog.com/lmlf001/archive/2007/09/08/31855.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多重继承与虚基类</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5910.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 14:19:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5910.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5910.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5910.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5910.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5910.html</trackback:ping><description><![CDATA[
		<span style="font-family: 宋体;">原文地址：http://cpp.ysu.edu.cn/jichu/pslyjc.htm<br /><br />多重继承</span>
		<span lang="EN-US">
				<o:p>
				</o:p>
		</span>
		<br />
		<span style="font-family: 宋体;">前面我们介绍的派生类只有一个基类，称为单基派生或单一继承。在实际运用中，我们经常需要派生类同时具有多个基类，这种方法称为多基派生或多重继承。</span>
		<br />
		<span lang="EN-US">2.1</span>
		<span style="font-family: 宋体;">多重继承的声明：</span>
		<span lang="EN-US">
				<o:p>
				</o:p>
		</span>
		<br />
		<span style="font-family: 宋体;">在</span>
		<span lang="EN-US">C++</span>
		<span style="font-family: 宋体;">中，声明具有两个以上基类的派生类与声明单基派生类的形式类似，只需将要继承的多个基类用逗号分开即可。</span>
		<br />
		<span style="font-family: 宋体;">在多重继承中，公有派生和私有派生对于基类成员在派生类的可访问性与单继承的规则相同。</span>
		<br />
		<span style="font-family: 宋体;">另外，对基类成员的访问必须是无二义的，若两个基类中具有同名的数据成员或成员函数，使用成员名限定来消除二义性，若派生类中新增成员或成员函数与基类成员或成员函数同名，则派生类会覆盖外层同名成员，也须使用作用域分辨符。</span>
		<br />
		<span lang="EN-US">2.2</span>
		<span style="font-family: 宋体;">多重继承的构造函数和析构函数：</span>
		<span lang="EN-US">
				<o:p>
				</o:p>
		</span>
		<br />
		<span style="font-family: 宋体;">多重继承的构造函数的定义形式与单继承构造函数的定义形式类似，只有</span>
		<span lang="EN-US">n</span>
		<span style="font-family: 宋体;">个基类的构造函数之间用“，”分隔。</span>
		<br />
		<span style="font-family: 宋体;">多重继承的构造函数的执行顺序与单继承构造函数的执行顺序相同，也是遵循先执行基类的构造函数，再执行对象成员的构造函数，最后执行派生类构造函数的原则。在多个基类之间，则严格按照派生类声明是从左到右的顺序来排列先后。而析构函数的执行顺序与构造函数的执行顺序相反。</span>
		<br />
		<span lang="EN-US">2.3</span>
		<span style="font-family: 宋体;">虚基类</span>
		<span lang="EN-US">:<o:p></o:p></span>
		<br />
		<span style="font-family: 宋体;">如果某个派生类的部分或全部直接基类是从另一个共同的基类派生而来，在这些基类中，从上一级基类继承来的成员就有相同的名称，则在这个派生类中访问这个共同的基类中的成员时，可能会产生二义性，此时，可定义虚基类。这就要求在其直接基类的定义中，使用关键字</span>
		<span lang="EN-US">virtual</span>
		<span style="font-family: 宋体;">将那个共同的基类定义为虚基类，其语法形式如下：</span>
		<br />
		<span lang="EN-US">
				<span style="">       </span>class<span style="">  </span></span>
		<span style="font-family: 宋体;">派生类名：</span>
		<span lang="EN-US">
				<span style="">  </span>virtual </span>
		<span style="font-family: 宋体;">派生方式</span>
		<span style="font-family: 宋体;">基类</span>
		<br />
		<span lang="EN-US">
				<span style="">    </span>
		</span>
		<span style="font-family: 宋体;">虚基类的初始化与一般的多重继承的初始化在语法上是一样的</span>
		<span style="font-family: 宋体;">，但构造函数的调用顺序不同，虚基类构造函数的调用顺序是这样规定的：</span>
		<br />
		<span lang="EN-US">1)</span>
		<span style="font-family: 宋体;">在同一层次中，先调用虚基类的构造函数，接下来依次是非虚基类的构造函数，对象成员的构造函数，派生类的构造函数。</span>
		<br />
		<span lang="EN-US">2)</span>
		<span style="font-family: 宋体;">若同一层次中包含多个虚基类，这些虚基类的构造函数按对他们说明的先后次序调用</span>
		<br />
		<span lang="EN-US">3)</span>
		<span style="font-family: 宋体;">若虚基类由非虚基类派生而来，则仍然先调用基类构造函数，再调用派生类构造函数。<br /><br /><br /></span>
<img src ="http://www.cppblog.com/lmlf001/aggbug/5910.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 22:19 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5910.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>volatile关键字</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5908.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 14:05:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5908.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5908.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5908.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5908.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5908.html</trackback:ping><description><![CDATA[
		<p>
				<font face="宋体" size="2">volatile关键字</font>
		</p>
		<p>
				<font face="宋体" size="2">volatile是c/c++中一个鲜为人知的关键字,该关键字告诉编译器不要持有变量的临时拷贝,它可以适用于基础类型<br />如：int,char,long......也适用于C的结构和C++的类。当对结构或者类对象使用volatile修饰的时候，结构或者<br />类的所有成员都会被视为volatile.</font>
		</p>
		<p>
				<font face="宋体" size="2">使用volatile并不会否定对CRITICAL_SECTION,Mutex,Event等同步对象的需要<br />例如：<br />int i;<br />i = i + 3;<br />无论如何，总是会有一小段时间，i会被放在一个寄存器中，因为算术运算只能在寄存器中进行。一般来说，volatitle<br />关键字适用于行与行之间，而不是放在行内。</font>
		</p>
		<p>
				<font face="宋体" size="2">我们先来实现一个简单的函数，来观察一下由编译器产生出来的汇编代码中的不足之处，并观察volatile关键字如何修正<br />这个不足之处。在这个函数体内存在一个busy loop(所谓busy loop也叫做busy waits,是一种高度浪费CPU时间的循环方法)</font>
		</p>
		<p>
				<font face="宋体" size="2">void getKey(char* pch)<br />{<br /> while (*pch == 0)<br />  ;<br />}</font>
		</p>
		<p>
				<font face="宋体" size="2">当你在VC开发环境中将最优化选项都关闭之后，编译这个程序，将获得以下结果(汇编代码)<br />;       while (*pch == 0)<br />$L27<br /> ; Load the address stored in pch<br /> mov eax, DWORD PTR _pch$[ebp]<br /> ; Load the character into the EAX register<br /> movsx eax, BYTE PTR [eax]<br /> ; Compare the value to zero<br /> test eax, eax<br /> ; If not zero, exit loop<br /> jne $L28<br /> ;<br /> jmp $L27<br />$L28<br />;}</font>
		</p>
		<p>
				<font face="宋体" size="2">这段没有优化的代码不断的载入适当的地址，载入地址中的内容，测试结果。效率相当的低，但是结果非常准确</font>
		</p>
		<p>
				<font face="宋体" size="2">现在我们再来看看将编译器的所有最优化选项开关都打开以后，重新编译程序，生成的汇编代码，和上面的代码<br />比较一下有什么不同<br />;{ <br /> ; Load the address stored in pch<br /> mov eax, DWORD PTR _pch$[esp-4]<br /> ; Load the character into the AL register<br /> movsx al, BYTE PTR [eax]<br />; while (*pch == 0)<br /> ; Compare the value in the AL register to zero<br /> test al, al<br /> ; If still zero, try again<br /> je SHORT $L84<br /> ;<br />;}</font>
		</p>
		<p>
				<font face="宋体" size="2">从代码的长度就可以看出来，比没有优化的情况要短的多。需要注意的是编译器把MOV指令放到了循环之外。这在<br />单线程中是一个非常好的优化，但是，在多线程应用程序中，如果另一个线程改变了变量的值，则循环永远不会<br />结束。被测试的值永远被放在寄存器中，所以该段代码在多线程的情况下，存在一个巨大的BUG。解决方法是重新<br />写一次getKey函数，并把参数pch声明为volatile,代码如下：</font>
		</p>
		<p>
				<font face="宋体" size="2">void getKey(volatile char* pch)<br />{<br /> while (*pch == 0)<br />  ;<br />}</font>
		</p>
		<p>
				<font face="宋体" size="2">这次的修改对于非最优化的版本没有任何影响，下面请看最优化后的结果：</font>
		</p>
		<p>
				<font face="宋体" size="2">;{<br /> ; Load the address stored in pch<br /> mov eax, DWORD PTR _pch$[esp-4]<br />;       while (*pch == 0)<br />$L84:<br /> ; Directly compare the value to zero<br /> cmp BYTE PTR [eax], 0<br /> ; If still zero, try again<br /> je SHORT $L84<br /> ;<br />;}</font>
		</p>
		<p>
				<font face="宋体" size="2">这次的修改结果比较完美，地址不会改变，所以地址声明被移动到循环之外。地址内容是volatile,所以每次循环<br />之中它不断的被重新检查。</font>
		</p>
		<p>
				<font face="宋体" size="2">把一个const volatile变量作为参数传递给函数是合法的。如此的声明意味着函数不能改变变量的值，但是变量的<br />值却可以被另一个线程在任何时间改变掉。</font>
		</p>
		<p>
				<font size="2">
						<font face="宋体">另：</font>
				</font>
		</p>
		<p>如果在一个多线程程序中想在两个函数中共享一个局部变量，需把变量声明为volatile类型</p>例如：<p></p><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> f1(</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> x)<br />{    <br />    </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">)x==0</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">);<br />    cout</span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">helo</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />    _endthread();<br />}<br /><br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> f2(</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">i)<br />{<br />    </span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> j</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;j</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">111</span><span style="color: rgb(0, 0, 0);">;j</span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);">);<br />    (</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">((</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">)i))</span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);">;<br />    _endthread();<br />}<br /><br /></span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> main()<br />{<br /></span><span style="color: rgb(0, 0, 255);">    int</span><span style="color: rgb(0, 0, 0);"> i</span><span style="color: rgb(0, 0, 0);">=0</span><span style="color: rgb(0, 0, 0);">;<br />    _beginthread((</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">)(</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">))f1,</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">i);    <br />    _beginthread((</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">)(</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">))f2,</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">i);<br />    </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);">(getch()</span><span style="color: rgb(0, 0, 0);">!=</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">q</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">;<br />    </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br />}</span></div><p>上例中，函数f1()中的循环控制条件永远为真，字符串"helo"得不到打印。</p><p>如果把f1()的参数类型改为volatitle void *x,则打印命令被实现。<br /></p><img src ="http://www.cppblog.com/lmlf001/aggbug/5908.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 22:05 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5908.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mutable关键字的用法</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5905.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 13:26:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5905.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5905.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5905.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5905.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5905.html</trackback:ping><description><![CDATA[
		<font face="宋体" size="2">关键字<span class="hilite1">mutable</span>是C++中一个不常用的关键字,他只能用于类的非静态和非常量数据成员<br />我们知道一个对象的状态由该对象的非静态数据成员决定,所以随着数据成员的改变,<br />对像的状态也会随之发生变化!</font>
		<p>
				<font face="宋体" size="2">如果一个类的成员函数被声明为const类型,表示该函数不会改变对象的状态,也就是<br />该函数不会修改类的非静态数据成员.但是有些时候需要在该类函数中对类的数据成员<br />进行赋值.这个时候就需要用到<span class="hilite1">mutable</span>关键字了</font>
		</p>
		<p>
				<font face="宋体" size="2">mutable关键字提示编译器该变量可以被类的const函数修改<br /></font>
		</p>
		<br />
<img src ="http://www.cppblog.com/lmlf001/aggbug/5905.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 21:26 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5905.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>explicit关键字用法</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5904.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 13:11:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5904.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5904.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5904.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5904.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5904.html</trackback:ping><description><![CDATA[explicit关键字用于取消构造函数的隐式转换，对有多个参数的构造函数使用explicit是个语法错误。<br /><p><br /></p><p>In C++ it is possible to declare constructors for a class, taking a
single parameter, and use those constructors for doing type conversion.
For example: <br /></p><pre><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> A {<br /></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">:<br />        A(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">);<br />};<br /><br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> f(A) {}<br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> g()<br />{<br />         A a1 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">37</span><span style="color: rgb(0, 0, 0);">;<br />         A a2 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> A(</span><span style="color: rgb(0, 0, 0);">47</span><span style="color: rgb(0, 0, 0);">);<br />         A a3(</span><span style="color: rgb(0, 0, 0);">57</span><span style="color: rgb(0, 0, 0);">);<br />         a1 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">67</span><span style="color: rgb(0, 0, 0);">;<br />         f(</span><span style="color: rgb(0, 0, 0);">77</span><span style="color: rgb(0, 0, 0);">);<br />}<br /></span></div><br />A declaration like:<br />	 A a1 = 37;<br />says to call the A(int) constructor to create an A object from
the integer value. Such a constructor is called a "converting
constructor". <br /></pre><p>However, this type of implicit conversion can
be confusing, and there is a way of disabling it, using a new keyword
"explicit" in the constructor declaration: <br /></p><pre><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> A {<br /></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">:<br />        </span><span style="color: rgb(0, 0, 255);">explicit</span><span style="color: rgb(0, 0, 0);"> A(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">);<br />};<br /><br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> f(A) {}<br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> g()<br />{<br />          A a1 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">37</span><span style="color: rgb(0, 0, 0);">;      </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> illegal</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">          A a2 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> A(</span><span style="color: rgb(0, 0, 0);">47</span><span style="color: rgb(0, 0, 0);">);   </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> OK</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">          A a3(</span><span style="color: rgb(0, 0, 0);">57</span><span style="color: rgb(0, 0, 0);">);       </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> OK</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">          a1 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">67</span><span style="color: rgb(0, 0, 0);">;        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> illegal</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">          f(</span><span style="color: rgb(0, 0, 0);">77</span><span style="color: rgb(0, 0, 0);">);          </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> illegal</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">}<br /><br /></span></div><br /></pre>Using the explicit keyword, a constructor is declared to be<br />"nonconverting", and explicit constructor syntax is required:<br /><br /><pre><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> A {<br /></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">:<br />        </span><span style="color: rgb(0, 0, 255);">explicit</span><span style="color: rgb(0, 0, 0);"> A(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">);<br />        };<br /><br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> f(A) {}<br /><br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> g()<br />{<br />        A a1 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> A(</span><span style="color: rgb(0, 0, 0);">37</span><span style="color: rgb(0, 0, 0);">);<br />        A a2 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> A(</span><span style="color: rgb(0, 0, 0);">47</span><span style="color: rgb(0, 0, 0);">);<br />        A a3(</span><span style="color: rgb(0, 0, 0);">57</span><span style="color: rgb(0, 0, 0);">);<br />        a1 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> A(</span><span style="color: rgb(0, 0, 0);">67</span><span style="color: rgb(0, 0, 0);">);<br />        f(A(</span><span style="color: rgb(0, 0, 0);">77</span><span style="color: rgb(0, 0, 0);">));<br />}<br /><br /></span></div><br /></pre><p>Note that an expression such as: <br /></p><pre>        A(47)<br /></pre><p>is closely related to function-style casts supported by C++. For example: <br /></p><pre>        double d = 12.34;<br /><br />        int i = int(d);<br /></pre><br /><img src ="http://www.cppblog.com/lmlf001/aggbug/5904.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 21:11 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5904.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++风格的类型转换的用法(ZZ)</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5903.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 12:52:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5903.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5903.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5903.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5903.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5903.html</trackback:ping><description><![CDATA[
		<div class="postbody">
				<font size="2">C++风格的类型转换的用法</font>
				<p>
						<font size="2">这是More Effecitve C++里的第二条对类型转换讲的很好，也很基础好懂。<br />Item 
      M2：尽量使用C++风格的类型转换<br />仔细想想地位卑贱的类型转换功能（cast），其在程序设计中的地位就象goto语句一样令人鄙视。但是它还不是无法令人忍受，因为当在某些紧要的关头，类型转换还是必需的，这时它是一个必需品。<br />不过C风格的类型转换并不代表所有的类型转换功能。<br />一
来它们过于粗鲁，能允许你在任何类型之间进行转换。不过如果要进行更精确的类型转换，这会是一个优点。在这些类型转换中存在着巨大的不同，例如把一个指向
const对象的指针（pointer-to-const-object）转换成指向非const对象的指针（pointer-to-non-const
-object）(即一个仅仅去除const的类型转换)，把一个指向基类的指针转换成指向子类的指针（即完全改变对象类型）。传统的C风格的类型转换不
对上述两种转换进行区分。（这一点也不令人惊讶，因为C风格的类型转换是为C语言设计的，而不是为C++语言设计的）。<br />二来C风格的类型转换在程
序语句中难以识别。在语法上，类型转换由圆括号和标识符组成，而这些可以用在C＋＋中的任何地方。这使得回答象这样一个最基本的有关类型转换的问题变得很
困难：“在这个程序中是否使用了类型转换？”。这是因为人工阅读很可能忽略了类型转换的语句，而利用象grep的工具程序也不能从语句构成上区分出它们
来。<br />C++通过引进四个新的类型转换操作符克服了C风格类型转换的缺点，这四个操作符是, 
      static_cast, const_cast, dynamic_cast, 
      和reinterpret_cast。在大多数情况下，对于这些操作符你只需要知道原来你习惯于这样写，<br />(type) 
      expression<br />而现在你总应该这样写：<br />static_cast&lt;type&gt;(expression)<br />例如，假设你想把一个int转换成double，以便让包含int类型变量的表达式产生出浮点数值的结果。如果用C风格的类型转换，你能这样写：<br />int 
      firstNumber, secondNumber;<br />...<br />double result = 
      ((double)firstNumber)/secondNumber；<br />如果用上述新的类型转换方法，你应该这样写：<br />double 
      result = 
      static_cast&lt;double&gt;(firstNumber)/secondNumber;<br />这样的类型转换不论是对人工还是对程序都很容易识别。<br />static_cast
在功能上基本上与C风格的类型转换一样强大，含义也一样。它也有功能上限制。例如，你不能用static_cast象用C风格的类型转换一样把
struct转换成int类型或者把double类型转换成指针类型，另外，static_cast不能从表达式中去除const属性，因为另一个新的类
型转换操作符const_cast有这样的功能。<br />其它新的C++类型转换操作符被用在需要更多限制的地方。const_cast用于类型转换掉表
达式的const或volatileness属性。通过使用const_cast，你向人们和编译器强调你通过类型转换想做的只是改变一些东西的
constness或者volatileness属性。这个含义被编译器所约束。如果你试图使用const_cast来完成修改constness
或者volatileness属性之外的事情，你的类型转换将被拒绝。下面是一些例子：<br />class Widget { ... 
      };<br />class SpecialWidget: public Widget { ... };<br />void 
      update(SpecialWidget *psw);<br />SpecialWidget sw; // sw 是一个非const 
      对象。<br />const SpecialWidget&amp; csw = sw; // csw 是sw的一个引用<br />// 它是一个const 
      对象<br />update(&amp;csw); // 错误!不能传递一个const SpecialWidget* 变量<br />// 
      给一个处理SpecialWidget*类型变量的函数<br />update(const_cast&lt;SpecialWidget*&gt;(&amp;csw));<br />// 
      正确，csw的const被显示地转换掉（<br />// 
      csw和sw两个变量值在update<br />//函数中能被更新）<br />update((SpecialWidget*)&amp;csw);<br />// 
      同上，但用了一个更难识别<br />//的C风格的类型转换<br />Widget *pw = new 
      SpecialWidget;<br />update(pw); // 错误！pw的类型是Widget*，但是<br />// 
      update函数处理的是SpecialWidget*类型<br />update(const_cast&lt;SpecialWidget*&gt;(pw));<br />// 
      错误！const_cast仅能被用在影响<br />// constness or volatileness的地方上。,<br />// 
      不能用在向继承子类进行类型转换。<br />到目前为止，const_cast最普通的用途就是转换掉对象的const属性。<br />第
二种特殊的类型转换符是dynamic_cast，它被用于安全地沿着类的继承关系向下进行类型转换。这就是说，你能用dynamic_cast把指向基
类的指针或引用转换成指向其派生类或其兄弟类的指针或引用，而且你能知道转换是否成功。失败的转换将返回空指针（当对指针进行类型转换时）或者抛出异常
（当对引用进行类型转换时）：<br />Widget 
      *pw;<br />...<br />update(dynamic_cast&lt;SpecialWidget*&gt;(pw));<br />// 
      正确，传递给update函数一个指针<br />// 是指向变量类型为SpecialWidget的pw的指针<br />// 
      如果pw确实指向一个对象,<br />// 否则传递过去的将使空指针。<br />void updateViaRef(SpecialWidget&amp; 
      rsw);<br />updateViaRef(dynamic_cast&lt;SpecialWidget&amp;&gt;(*pw));<br />//正确。传递给updateViaRef函数<br />// 
      SpecialWidget pw 指针，如果pw<br />// 确实指向了某个对象<br />// 
      否则将抛出异常<br />dynamic_casts在帮助你浏览继承层次上是有限制的。它不能被用于缺乏虚函数的类型上（参见条款M24），也不能用它来转换掉constness：<br />int 
      firstNumber, secondNumber;<br />...<br />double result = 
      dynamic_cast&lt;double&gt;(firstNumber)/secondNumber;<br />// 
      错误！没有继承关系<br />const SpecialWidget 
      sw;<br />...<br />update(dynamic_cast&lt;SpecialWidget*&gt;(&amp;sw));<br />// 
      错误! dynamic_cast不能转换<br />// 
      掉const。<br />如你想在没有继承关系的类型中进行转换，你可能想到static_cast。如果是为了去除const，你总得用const_cast。<br />这四个类型转换符中的最后一个是reinterpret_cast。使用这个操作符的类型转换，其的转换结果几乎都是执行期定义（implementation-defined）。因此，使用reinterpret_casts的代码很难移植。<br />reinterpret_casts的最普通的用途就是在函数指针类型之间进行转换。例如，假设你有一个函数指针数组：<br />typedef 
      void (*FuncPtr)(); // FuncPtr is 一个指向函数<br />// 的指针，该函数没有参数<br />// 
      返回值类型为void<br />FuncPtr funcPtrArray[10]; // funcPtrArray 是一个能容纳<br />// 
      10个FuncPtrs指针的数组<br />让我们假设你希望（因为某些莫名其妙的原因）把一个指向下面函数的指针存入funcPtrArray数组：<br />int 
      doSomething();<br />你不能不经过类型转换而直接去做，因为doSomething函数对于funcPtrArray数组来说有一个错误的类型。在FuncPtrArray数组里的函数返回值是void类型，而doSomething函数返回值是int类型。<br />funcPtrArray[0] 
      = &amp;doSomething; // 
      错误！类型不匹配<br />reinterpret_cast可以让你迫使编译器以你的方法去看待它们：<br />funcPtrArray[0] = // 
      this 
      compiles<br />reinterpret_cast&lt;FuncPtr&gt;(&amp;doSomething);<br />转换函数指针的代码是不可移植的（C++不保证所有的函数指针都被用一样的方法表示），在一些情况下这样的转换会产生不正确的结果（参见条款M31），所以你应该避免转换函数指针类型，除非你处于着背水一战和尖刀架喉的危急时刻。一把锋利的刀。一把非常锋利的刀。<br />如果你使用的编译器缺乏对新的类型转换方式的支持，你可以用传统的类型转换方法代替static_cast, 
      const_cast, 以及reinterpret_cast。也可以用下面的宏替换来模拟新的类型转换语法：<br />#define 
      static_cast(TYPE,EXPR) ((TYPE)(EXPR))<br />#define const_cast(TYPE,EXPR) 
      ((TYPE)(EXPR))<br />#define reinterpret_cast(TYPE,EXPR) 
      ((TYPE)(EXPR))<br />你可以象这样使用使用：<br />double result = static_cast(double, 
      firstNumber)/secondNumber;<br />update(const_cast(SpecialWidget*, 
      &amp;sw));<br />funcPtrArray[0] = reinterpret_cast(FuncPtr, 
      &amp;doSomething);<br />这些模拟不会象真实的操作符一样安全，但是当你的编译器可以支持新的的类型转换时，它们可以简化你把代码升级的过程。<br />没
有一个容易的方法来模拟dynamic_cast的操作，但是很多函数库提供了函数，安全地在派生类与基类之间进行类型转换。如果你没有这些函数而你有必
须进行这样的类型转换，你也可以回到C风格的类型转换方法上，但是这样的话你将不能获知类型转换是否失败。当然，你也可以定义一个宏来模拟
dynamic_cast的功能，就象模拟其它的类型转换一样：<br />#define 
      dynamic_cast(TYPE,EXPR) 
      (TYPE)(EXPR)<br />请记住，这个模拟并不能完全实现dynamic_cast的功能，它没有办法知道转换是否失败。<br />我
知道，是的，我知道，新的类型转换操作符不是很美观而且用键盘键入也很麻烦。如果你发现它们看上去实在令人讨厌，C风格的类型转换还可以继续使用并且合
法。然而，正是因为新的类型转换符缺乏美感才能使它弥补了在含义精确性和可辨认性上的缺点。并且，使用新类型转换符的程序更容易被解析（不论是对人工还是
对于工具程序），它们允许编译器检测出原来不能发现的错误。这些都是放弃C风格类型转换方法的强有力的理由。还有第三个理由：也许让类型转换符不美观和键
入麻烦是一件好事。</font>
				</p>
		</div>
<img src ="http://www.cppblog.com/lmlf001/aggbug/5903.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 20:52 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5903.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++string类常用函数</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5883.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 08:00:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5883.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5883.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5883.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5883.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5883.html</trackback:ping><description><![CDATA[
		<p>
				<font size="3">string类的构造函数：<br />
string(const char *s);    //用c字符串s初始化<br />
string(int n,char c);     //用n个字符c初始化<br />
此外，string类还支持默认构造函数和复制构造函数，如string s1；string 
s2="hello"；都是正确的写法。当构造的string太长而无法表达时会抛出length_error异常</font>
		</p>
		<p>
				<font size="3">string类的字符操作：<br />
const char &amp;operator[](int n)const;<br />
const char &amp;at(int n)const;<br />
char &amp;operator[](int n);<br />
char &amp;at(int n);<br />
operator[]和at()均返回当前字符串中第n个字符的位置，但at函数提供范围检查，当越界时会抛出out_of_range异常，下标运算符[]不提供检查访问。<br />
const char *data()const;//返回一个非null终止的c字符数组<br />
const char *c_str()const;//返回一个以null终止的c字符串<br />
int copy(char *s, int n, int pos = 0) 
const;//把当前串中以pos开始的n个字符拷贝到以s为起始位置的字符数组中，返回实际拷贝的数目</font>
		</p>
		<p>
				<font size="3">string的特性描述:<br />
int capacity()const;    //返回当前容量（即string中不必增加内存即可存放的元素个数）<br />
int max_size()const;    //返回string对象中可存放的最大字符串的长度<br />
int size()const;        //返回当前字符串的大小<br />
int length()const;       //返回当前字符串的长度<br />
bool empty()const;        //当前字符串是否为空<br />
void resize(int len,char c);//把字符串当前大小置为len，并用字符c填充不足的部分</font>
		</p>
		<p>
				<font size="3">string类的输入输出操作:<br />
string类重载运算符operator&gt;&gt;用于输入，同样重载运算符operator&lt;&lt;用于输出操作。<br />
函数getline(istream &amp;in,string &amp;s);用于从输入流in中读取字符串到s中，以换行符'\n'分开。<br />
 </font>
		</p>
		<p>
				<font size="3">string的赋值：<br />
string &amp;operator=(const string &amp;s);//把字符串s赋给当前字符串<br />
string &amp;assign(const char *s);//用c类型字符串s赋值<br />
string &amp;assign(const char *s,int n);//用c字符串s开始的n个字符赋值<br />
string &amp;assign(const string &amp;s);//把字符串s赋给当前字符串<br />
string &amp;assign(int n,char c);//用n个字符c赋值给当前字符串<br />
string &amp;assign(const string &amp;s,int start,int n);//把字符串s中从start开始的n个字符赋给当前字符串<br />
string &amp;assign(const_iterator first,const_itertor 
last);//把first和last迭代器之间的部分赋给字符串<br />
 </font>
		</p>
		<p>
				<font size="3">string的连接：<br /><code>
						string &amp;operator+=(const string 
&amp;s);//把字符串s连接到当前字符串的结尾
				</code></font>
				<font size="3">
						<br />
string &amp;append(const char *s);            //把c类型字符串s连接到当前字符串结尾<br /><code>
						string &amp;append(const char *s,int 
n);//把c类型字符串s的前n个字符连接到当前字符串结尾<br />
string &amp;append(const string &amp;s);    //同operator+=()<br />
string &amp;append(const string &amp;s,int pos,int n);//把字符串s中从pos开始的n个字符连接到当前字符串的结尾<br />
string &amp;append(int n,char c);        //在当前字符串结尾添加n个字符c<br />
string &amp;append(const_iterator first,const_iterator 
last);//把迭代器first和last之间的部分连接到当前字符串的结尾
				</code></font>
				<font size="3">
						<br />
 </font>
		</p>
		<p>
				<font size="3">
						<code>
						string的比较：<br />
bool operator==(const string &amp;s1,const string &amp;s2)const;//比较两个字符串是否相等<br />
运算符"&gt;","&lt;","&gt;=","&lt;=","!="均被重载用于字符串的比较；<br />
int compare(const string &amp;s) const;//比较当前字符串和s的大小<br />
int compare(int pos, int n,const string &amp;s)const;//比较当前字符串从pos开始的n个字符组成的字符串与s的大小<br />
int compare(int pos, int n,const string &amp;s,int pos2,int 
n2)const;//比较当前字符串从pos开始的n个字符组成的字符串与s中pos2开始的n2个字符组成的字符串的大小<br />
int compare(const char *s) const;<br />
int compare(int pos, int n,const char *s) const;<br />
int compare(int pos, int n,const char *s, int pos2) const;<br />
compare函数在&gt;时返回1，&lt;时返回-1，==时返回0 
				</code>
				</font>
				<font size="3"> </font>
		</p>
		<p>
				<font size="3">
						<code>
						string的子串：<br />
string substr(int pos = 0,int n = npos) const;//返回pos开始的n个字符组成的字符串 
				</code>
				</font>
		</p>
		<p>
				<font size="3">
						<br />
string的交换：<br />
void swap(string &amp;s2);    //交换当前字符串与s2的值</font>
		</p>
		<p>
				<font size="3"> </font>
		</p>
		<p>
				<font size="3">string类的查找函数：</font>
		</p>
		<p>
				<font size="3">
						<code>
						int find(char c, int pos = 0) 
const;//从pos开始查找字符c在当前字符串的位置<br />
int find(const char *s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置<br />
int find(const char *s, int pos, int n) const;//从pos开始查找字符串s中前n个字符在当前串中的位置<br />
int find(const string &amp;s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置<br />
//查找成功时返回所在位置，失败返回string::npos的值
				</code>
				</font>
		</p>
		<p>
				<font size="3">
						<code>
						int rfind(char c, int pos = npos) 
const;//从pos开始从后向前查找字符c在当前串中的位置<br />
int rfind(const char *s, int pos = npos) const;<br />
int rfind(const char *s, int pos, int n = npos) const;<br />
int rfind(const string &amp;s,int pos = npos) const;<br />
//从pos开始从后向前查找字符串s中前n个字符组成的字符串在当前串中的位置，成功返回所在位置，失败时返回string::npos的值
				</code>
				</font>
		</p>
		<p>
				<font size="3">
						<code>
						int find_first_of(char c, int pos = 0) 
const;//从pos开始查找字符c第一次出现的位置<br />
int find_first_of(const char *s, int pos = 0) const;<br />
int find_first_of(const char *s, int pos, int n) const;<br />
int find_first_of(const string &amp;s,int pos = 0) const;<br />
//从pos开始查找当前串中第一个在s的前n个字符组成的数组里的字符的位置。查找失败返回string::npos
				</code>
				</font>
		</p>
		<p>
				<font size="3">
						<code>
						int find_first_not_of(char c, int pos = 0) const;<br />
int find_first_not_of(const char *s, int pos = 0) const;<br />
int find_first_not_of(const char *s, int pos,int n) const;<br />
int find_first_not_of(const string &amp;s,int pos = 0) const;<br />
//从当前串中查找第一个不在串s中的字符出现的位置，失败返回string::npos
				</code>
				</font>
		</p>
		<p>
				<font size="3">
						<code>
						int find_last_of(char c, int pos = npos) const;<br />
int find_last_of(const char *s, int pos = npos) const;<br />
int find_last_of(const char *s, int pos, int n = npos) const;<br />
int find_last_of(const string &amp;s,int pos = npos) const;
				</code>
				</font>
		</p>
		<p>
				<font size="3">
						<code>
						int find_last_not_of(char c, int pos = npos) const;<br />
int find_last_not_of(const char *s, int pos = npos) const;<br />
int find_last_not_of(const char *s, int pos,  int n) const;<br />
int find_last_not_of(const string &amp;s,int pos = npos) const;<br />
//find_last_of和find_last_not_of与find_first_of和find_first_not_of相似，只不过是从后向前查找
				</code>
				</font>
		</p>
		<p>
				<font size="3"> </font>
		</p>
		<p>
				<font size="3">string类的替换函数：</font>
		</p>
		<p>
				<font size="3">
						<code>
						string &amp;replace(int p0, int n0,const char 
*s);//删除从p0开始的n0个字符，然后在p0处插入串s<br />
string &amp;replace(int p0, int n0,const char *s, int 
n);//删除p0开始的n0个字符，然后在p0处插入字符串s的前n个字符<br />
string &amp;replace(int p0, int n0,const string &amp;s);//删除从p0开始的n0个字符，然后在p0处插入串s<br />
string &amp;replace(int p0, int n0,const string &amp;s, int pos, int 
n);//删除p0开始的n0个字符，然后在p0处插入串s中从pos开始的n个字符<br />
string &amp;replace(int p0, int n0,int n, char c);//删除p0开始的n0个字符，然后在p0处插入n个字符c<br />
string &amp;replace(iterator first0, iterator last0,const char 
*s);//把[first0，last0）之间的部分替换为字符串s<br />
string &amp;replace(iterator first0, iterator last0,const char *s, int 
n);//把[first0，last0）之间的部分替换为s的前n个字符<br />
string &amp;replace(iterator first0, iterator last0,const string 
&amp;s);//把[first0，last0）之间的部分替换为串s<br />
string &amp;replace(iterator first0, iterator last0,int n, char 
c);//把[first0，last0）之间的部分替换为n个字符c<br />
string &amp;replace(iterator first0, iterator last0,const_iterator first, 
const_iterator last);//把[first0，last0）之间的部分替换成[first，last）之间的字符串
				</code>
				</font>
		</p>
		<p>
				<font size="3">string类的插入函数：</font>
		</p>
		<p>
				<font size="3">
						<code>
						string &amp;insert(int p0, const char *s);<br />
string &amp;insert(int p0, const char *s, int n);<br />
string &amp;insert(int p0,const string &amp;s);<br />
string &amp;insert(int p0,const string &amp;s, int pos, int n);<br />
//前4个函数在p0位置插入字符串s中pos开始的前n个字符<br />
string &amp;insert(int p0, int n, char c);//此函数在p0处插入n个字符c<br />
iterator insert(iterator it, char c);//在it处插入字符c，返回插入后迭代器的位置<br />
void insert(iterator it, const_iterator first, const_iterator last);//在it处插入[first，last）之间的字符<br />
void insert(iterator it, int n, char c);//在it处插入n个字符c<br />
 
				</code>
				</font>
		</p>
		<p>
				<font size="3">string类的删除函数</font>
		</p>
		<p>
				<font size="3">iterator erase(iterator first, iterator last);//删除[first，last）之间的所有字符，返回删除后迭代器的位置<br />
iterator erase(iterator it);//删除it指向的字符，返回删除后迭代器的位置<br />
string &amp;erase(int pos = 0, int n = npos);//删除pos开始的n个字符，返回修改后的字符串</font>
		</p>
		<p>
				<font size="3"> </font>
		</p>
		<p>
				<font size="3">string类的迭代器处理：</font>
		</p>
		<p>
				<font size="3">string类提供了向前和向后遍历的迭代器iterator，迭代器提供了访问各个字符的语法，类似于指针操作，迭代器不检查范围。<br />
用string::iterator或string::const_iterator声明迭代器变量，const_iterator不允许改变迭代的内容。常用迭代器函数有：<br />
const_iterator begin()const;<br />
iterator begin();                
//返回string的起始位置<br />
const_iterator end()const;<br />
iterator end();                    
//返回string的最后一个字符后面的位置<br />
const_iterator rbegin()const;<br />
iterator rbegin();                
//返回string的最后一个字符的位置<br />
const_iterator rend()const;<br />
iterator rend();                    
//返回string第一个字符位置的前面<br />
rbegin和rend用于从后向前的迭代访问，通过设置迭代器string::reverse_iterator,string::const_reverse_iterator实现</font>
		</p>
		<p>
				<font size="3"> </font>
		</p>
		<p>
				<font size="3">字符串流处理：</font>
		</p>
		<p>
				<font size="3">通过定义ostringstream和istringstream变量实现，&lt;sstream&gt;头文件中<br />
例如：<br />
    string input("hello,this is a test");<br />
    istringstream is(input);<br />
    string s1,s2,s3,s4;<br />
    is&gt;&gt;s1&gt;&gt;s2&gt;&gt;s3&gt;&gt;s4;//s1="hello,this",s2="is",s3="a",s4="test"<br />
    ostringstream os;<br />
    os&lt;&lt;s1&lt;&lt;s2&lt;&lt;s3&lt;&lt;s4;<br />
    cout&lt;&lt;os.str();</font>
		</p>
		<p>
				<font size="3"> </font>
		</p>
<img src ="http://www.cppblog.com/lmlf001/aggbug/5883.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 16:00 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5883.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 过度使用C++模板(overdoing C++ templates)（ZZ）</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5880.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 06:30:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5880.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5880.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5880.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5880.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5880.html</trackback:ping><description><![CDATA[
		<h2> 过度使用C++模板(overdoing C++ templates) </h2>
作者：Steve Donovan. <br />
翻译: <a href="http://www.winterxy.com/" target="_top">Winter</a><br />
原文: <a href="http://www.informit.com/articles/article.asp?p=26017&amp;rl=1" target="_top">Overdoing C++ Templates</a><hr />
大约每隔十年，都会出现一个编程新概念，宣布自己是以往概念的继承者。我们也再一次相信，从今往后软件比以前更可靠，更容易build，或者更有意思(没
有人相信它会比以前更小或者更快)。在70年代，有结构编程；在80年代，开始了面向对象编程；从90年代中期，出现了范型编程(generic
programming)。范型编程得名于其用模板而使代码重用的高效技术(范型类和范型函数)。
<p>模板类和模板函数都是非常有用的工具。例如sqr()函数可以计算平方数，任何定义了乘法运算的数据类型（数字，矩阵）都适用。标准容器类(如
list)都是模板，这样对于每个新类型无需重写了，这正是使用旧版的C++时真正头疼的事情，因此我认为ISO的标准是个伟大的进步。然而，在这个过程
中有些东西用得过头了。
</p><p>例如：标准库中得string 和iostream 都是使用"character
traits"类型作为参数。这意味着同一个basic_string&lt;&gt;类可以用于ASCII字符串，也可用于Unicode，甚至用于火
星人的三字节字符串（原则虽然如此，但许多版本都只是实现了ASCII字符串，看起来有点滑稽）。标准要求这些常用类必须实现成模板形式，而这些类几乎涉
及到所有C++应用。
</p><p>但是这对性能和调试会带来许多麻烦。下面几个试验解释了这个问题（本试验使用的编译器为VC++6.0)。编译器同时支持新风格的
iostream（使用模板）和经典风格的iostream, 因此我们能比较他们二者的版本实现。第一个测试程序当然是使用"Hello,
Word"了，新风格的编译时间是经典风格的2倍。另一个更正规的例子大约有200行，每行输出10个变量用于计数。这个测试程序最显著的结论是编译速
度：新风格版本花了10秒编译完成，而旧版本只使用了1.5秒。10秒时间可并不少，可以完成很多事情。另外，新风格版本的可执行文件的大小为115K，
而旧版本只有70K。你的测试数据可能有些出入，但是整体结论是一样的：当使用新版本时，会有更慢的编译速度和更大的可执行文件。这并不是因为微软公司编
译器的问题，使用GCC测试也会得到同样的结论。
</p><p>当然，和过去不一样，可执行文件的大小并不是那么重要，现在，可编程设备种类正快速增长，包括许多信息应用，如遥控、手机、智能冰箱、基
于蓝牙技术的咖啡机等等，在这些应用中内存近几年都会是十分宝贵的资源。使用标准iostream
而产生的额外的二进制文件，来源于内联了整个模板类的代码，要是没有code
bload工具，你很难优化那些重要的操作。对我来说，编译时间问题更严重一些，因为这样意味着更长的等待，从而失去了开发中非常重要原则：互动原则。
</p><p>
现在我们来考虑调试的问题。标准库中string 类的模板实现非常聪明，但并不适合于调试。你会面临使用超长名字的编译器和调试器的信息：
</p><div class="fragment"><pre><font color="brown">class</font> std::basic_string&lt;<font color="brown">char</font>,<font color="brown">struct</font> std::char_traits&lt;<font color="brown">char</font>&gt;,<font color="brown">class</font> std::allocator&lt;<font color="brown">char</font>&gt;&gt;</pre></div>同
样对于非常有用的容器 map &lt; string,string &gt; ,
你可以去想象其复杂性。这些名字太长了，以至于产生数十个内部名字被截断的警告。对于初学者来说，std::string
应该设计得尽可能透明，而不应该让他们面临许多语言内置得一些特性。当输出了编译错误信息后，在技术上讲，应该是可以查找到所有的 typedef
。我在 UnderC 项目中就试图这么做。Verity Stob
建议编写一个后置的处理器来翻译这些错误信息，我倒希望这是她这么做只是开个玩笑。如果不使用这么复杂的类型，这个问题就会容易处理的多。我在C++开发
上的秘诀就是（我首次坦诚的公开这个秘密): 在稍微大一点的工程中使用一个兼容的string 类来替换std::string 的头文件.
有时我会重新build 这些标准的头文件，用来检测是否我的库还能正常使用，但让其他人为如何提高其性能而努力。
<p>当然，在许多应用中我们都需要这种std::string提供的灵活性，例如，需要同时处理ASCII
和Unicode字符串，或者需要定制自己的allocator
等等。但这并不是普遍需求(通常程序员要么只处理ASCII，要么只处理Unicode ),
看起来对于程序员承担这种范型机制有些不公平。这种机制确实让标准库的设计者觉得很有意思，但增加了应用开发程序员使用的复杂度。这似乎颠倒了这个原则：
良好的标准库设计应该隐藏其实现的复杂度，而让用户直接使用。但std::string
对其实现的复杂度隐藏得并不够，导致在用户使用过程中不断的遇到设计中的问题。我们不能要求标准库的用户都是专家。标准坚持要求这种特定的实现方式，和标
准库的设计初衷相违背，其初衷是只提供公共的接口和包含一些特定功能的类库。自然，这种范型模板对于那些真正去要他们的人是一直有效的。
</p><p>这些细节考虑同样应用于标准容器，例如list&lt;&gt;容器，list
有一些额外的默认模板参数，用于定义了默认的allocator。当然自己定义allocator
十分有用，但绝大多数人不需要自己去实现。这些泛化的版本完全可以作为单独的模板提供。我承认这样做会让标准库的设计在技术上变得没有以前有意思，但这些
库在设计之初就应该考虑到最终用户。篡改一下C++的颂歌：用户不应该为他们不需要的东西买单。
</p><p>
当我们不需要模板的时候，我们不得不使用模板。除此之外，在C＋＋中用范型编程还会遇到另一个的问题。大多数人都同意，标准的algorithm 十分有用。如果你有一个整型的vector, 你可以直接使用下面的语句来排序：
</p><div class="fragment"><pre>sort(v.begin(),v.end());</pre></div>
因为int型数据的比较函数时内联的，而且这种范型算法比旧版本的qsort()函数速度还快，也更容易使用，特别是使用用户自定义类型的vector. copy()函数也可以在任何时候高效率地拷贝任何数据。
<p>
但有些应用理解起来十分晦涩：
</p><div class="fragment"><pre>copy_if(v.begin(),v.end(),ostream_iterator&lt;<font color="brown">int</font>&gt;(cout) bind2nd(greater&lt;<font color="brown">int</font>&gt;(),7));</pre></div>
如果要写得严格一点，每个名字都应该加上std::前缀，这里假定所有变量都是使用全局命名空间，或单独使用命令或用其他方法。用Stroustrup (C++的创始人)的例子更容易说明问题，这个例子把所有的整型数输出到终端： 
<div class="fragment"><pre>vector&lt;<font color="brown">int</font>&gt;::iterator li;<br /><font color="brown">for</font> (li = v.begin(); li != v.end(); ++li)<br /><font color="brown">if</font> (*li &gt; 7) cout &lt;&lt; *li;</pre></div>Stroustrup
告诉我们如果使用显示的循环是"麻烦而又容易产生错误",
但我看不出使用第一个版本有什么优势。显然，人们能习惯这种方式，人类的适应性很强，作为专业人士，我们也不得不学习这个新概念。但是，这样做并没有减少
多少麻烦，而且我们可以证明这样做可读性更差，更不灵活。同时，它还会限制你的设计。例如，假设我们有一个Shape * 的指针list,
我们可以通过下面的调用方式来画出他们自己的形状：
<div class="fragment"><pre>for_each(ls.begin(),ls.end(),<br />bind2nd(mem_fun(&amp;Shape::draw),canvas));</pre></div>
也可以选择这种方式：
<div class="fragment"><pre>ShapeList::iterator li;<br /><font color="brown">for</font> (li = ls.begin(); li != ls.end(); ++li)<br />(*li)-&gt;draw(canvas);</pre></div>现
在假设我需要修改我的设计，我只想画那些满足某种要求的图形（而且不希望把这些需求包在shape类里面),
那么我只需要在显式的循环中增加一条if条件语句。如果要使用范型概念，我唯一能想到的方式定义一个函数，然后使用for_each()算法。使用设计模
式一书中的术语，第一个例子是一个内部迭代器(internal iterator)，第二个例子式一个外部跌倒器(external
iterator). 作者认为C++
并不擅长使用内部迭代器，我想我们还是应该考虑语言的局限性。其实问题在于在C++中过度应用范型概念--从而导致不必要的难度。C++
完全不支持一般的匿名函数(anonymous functions)如LIST, SmallTalk,
Ruby等。C++中的匿名函数或许看起来和下面一样，可能某天有人会实现它：
<div class="fragment"><pre>for_each(ls.begin(),ls.end(),<br /><font color="brown">void</font> lambda(Shape *p) { p-&gt;draw(canvas); }); </pre></div><p>C++
是一种不可思议的编程语言，小到手机，大到跨国际网络，都有其应用。它非常灵活，能够支持多种编程风格，但这种灵活同样也是其问题所在。编程的艺术在于为
特定的问题选择合适编程风格，就像老师总提醒写作文是要选择好的风格一样。我并不想诋毁 C++
标准库，这里面包含了许多人的辛勤劳动，并为大家提供了一个公共平台。我对于这个标准的态度是，它和范型编程联系过于紧密，从而变成了在说明什么风格是好
的编程风格(例如，算法中明显倾向于不要使用显式循环),
同时它也让程序员们不得不介入一些实现细节(如basic_string&lt;&gt;)，这样做让人们更加觉得C++
是只是内核工程师们的编程语言。
</p><img src ="http://www.cppblog.com/lmlf001/aggbug/5880.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 14:30 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5880.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C可变长参数表问题</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5874.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 05:28:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5874.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5874.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5874.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5874.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5874.html</trackback:ping><description><![CDATA[原文地址：http://www.programfan.com/club/showbbs.asp?id=82615 <br /><br />
				  	一、什么是可变参数<br />
我们在C语言编程中有时会遇到一些参数个数可变的函数,例如printf()函数,其函数原型为: <br />
int printf( const char* format, ...); <br />
它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的（用三个点“…”做参数占位符）,实际调用时可以有以下的形式: printf("%d",i); <br />
printf("%s",s); <br />
printf("the number is %d ,string is:%s", i, s);    <br />
以上这些东西已为大家所熟悉。但是究竟如何写可变参数的C函数以及这些可变参数的函数编译器是如何实现，这个问题却一直困扰了我好久。本文就这个翁饨幸恍┨教?希望能对大家有些帮助.<br />
long sum(int i,...)<br />
{<br />
  int *p,j;<br />
  long s = 0;<br />
  p = &amp;i+1;<br />
  for (j=0;j&lt;i;j++)<br />
    s += p[j];<br />
   return s;<br />
}<br />
long Sum = sum(3,1,2,3);<br />
printf("%ld",Sum);<br />
Sum == 6<br />
二、写一个简单的可变参数的C函数 <br />
先看例子程序。该函数至少有一个整数参数,其后占位符…，表示后面参数的个数不定. 在这个例子里，所有的输入参数必须都是整数，函数的功能只是打印所有参数的值.<br />
函数代码如下：<br />
//示例代码1：可变参数函数的使用<br />
#include "stdio.h"<br />
#include "stdarg.h"<br />
void simple_va_fun(int start, ...) <br />
{ <br />
    va_list arg_ptr; <br />
    int nArgValue =start;<br />
    int nArgCout=0;     //可变参数的数目<br />
    va_start(arg_ptr,start); //以固定参数的地址为起点确定变参的内存起始地址。<br />
    do <br />
    {<br />
        ++nArgCout;<br />
        printf("the %d th arg: %d",nArgCout,nArgValue);     //输出各参数的值<br />
        nArgValue = va_arg(arg_ptr,int);                      //得到下一个可变参数的值<br />
    } while(nArgValue != -1);                <br />
    return; <br />
}<br />
int main(int argc, char* argv[])<br />
{<br />
    simple_va_fun(100,-1); <br />
    simple_va_fun(100,200,-1); <br />
       return 0;<br />
}<br />
下面解释一下这些代码<br />
从这个函数的实现可以看到,我们使用可变参数应该有以下步骤: <br />
⑴由于在程序中将用到以下这些宏: <br />
void va_start( va_list arg_ptr, prev_param ); <br />
type va_arg( va_list arg_ptr, type ); <br />
void va_end( va_list arg_ptr ); <br />
va在这里是variable-argument(可变参数)的意思. <br />
这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件.<br />
⑵函数里首先定义一个va_list型的变量,这里是arg_ptr,这个变 <br />
量是存储参数地址的指针.因为得到参数的地址之后，再结合参数的类型，才能得到参数的值。<br />
⑶然后用va_start宏初始化⑵中定义的变量arg_ptr,这个宏的第二个参数是可变参数列表的前一个参数,即最后一个固定参数. <br />
⑷然后依次用va_arg宏使arg_ptr返回可变参数的地址,得到这个地址之后，结合参数的类型，就可以得到参数的值。<br />
⑸设定结束条件，这里的条件就是判断参数值是否为-1。注意被调的函数在调用时是不知道可变参数的正确数目的，程序员必须自己在代码中指明结束条件。至于为什么它不会知道参数的数目，读者在看完这几个宏的内部实现机制后，自然就会明白。<br /><br /><br /><br /><br />
--------------------------------------------------------------------------------<br /><br /><br />
(二)可变参数在编译器中的处理 <br />
我们知道va_start,va_arg,va_end是在stdarg.h中被定义成宏的, 由于1)硬件平台的不同
2)编译器的不同,所以定义的宏也有所不同,下面看一下VC++6.0中stdarg.h里的代码（文件的路径为VC安装目录下的\vc98\
include\stdarg.h）<br />
typedef char *  va_list;<br />
#define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) &amp; ~(sizeof(int) - 1) )<br />
#define va_start(ap,v)  ( ap = (va_list)&amp;v + _INTSIZEOF(v) )<br />
#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )<br />
#define va_end(ap)      ( ap = (va_list)0 )<br />
下面我们解释这些代码的含义：<br />
1、首先把va_list被定义成char*，这是因为在我们目前所用的PC机上，字符指针类型可以用来存储内存单元地址。而在有的机器上va_list是被定义成void*的<br />
2、定义_INTSIZEOF(n)主要是为了某些需要内存的对齐的系统.这个宏的目的是为了得到最后一个固定参数的实际内存大?gt;&gt;Ｔ谖业幕魃现苯佑胹izeof运朔创妫猿绦虻脑诵薪峁挂裁挥杏跋臁＃ê笪慕吹轿易约旱氖迪郑?<br />
3、va_start的定义为 &amp;v+_INTSIZEOF(v)
,这里&amp;v是最后一个固定参数的起始地址，再加上其实际占用大小后，就得到了第一个可变参数的起始内存地址。所以我们运行va_start
(ap, v)以后,ap指向第一个可变参数在的内存地址,有了这个地址，以后的事情就简单了。 <br />
这里要知道两个事情：<br />
    ⑴在intel+windows的机器上，函数栈的方向是向下的，栈顶指针的内存地址低于栈底指针，所以先进栈的数据是存放在内存的高地址处。<br />
    (2)在VC等绝大多数C编译器中，默认情况下，参数进栈的顺序是由右向左的，因此，参数进栈以后的内存模型如下图所示：最后一个固定参数的地址位于第一个可变参数之下，并且是连续存储的。<br />
|——————————————————————————|<br />
|  最后一个可变参数             |   -&gt;高内存地址处<br />
|——————————————————————————|<br />
   ...................<br />
|——————————————————————————|<br />
|  第N个可变参数              |     -&gt;va_arg(arg_ptr,int)后arg_ptr所指的地方,<br />
|                               |     即第N个可变参数的地址。<br />
|——————————————— |     <br />
   ………………………….<br />
|——————————————————————————|<br />
|  第一个可变参数               |     -&gt;va_start(arg_ptr,start)后arg_ptr所指的地方<br />
|                               |     即第一个可变参数的地址<br />
|——————————————— |     <br />
|———————————————————————— ——|<br />
|                               |<br />
|  最后一个固定参数             |    -&gt; start的起始地址<br />
|—————————————— —|       .................<br />
|—————————————————————————— |<br />
|                               |  <br />
|——————————————— |  -&gt; 低内存地址处<br /><br />
(4) va_arg():有了va_start的良好基础，我们取得了第一个可变参数的地址，在va_arg()里的任务就是根据指定的参数类型取得本参数的值，并且把指针调到弦桓霾问钠鹗嫉刂贰?<br />
因此，现在再来看va_arg()的实现就应该心中有数了：<br />
#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )<br />
这个宏做了两个事情，<br />
       ①用用户输入的类型名对参数地址进行强制类型转换，得到用户所需要的值<br />
   ②计算出本参数的实际大小，将指针调到本参数的结尾，也就是下一个参数的首地址，以便后续处理。<br />
(5)va_end宏的解释：x86平台定义为ap=(char*)0;使ap不再
指向堆栈,而是跟NULL一样.有些直接定义为((void*)0),这样编译器不会为va_end产生代码,例如gcc在linux的x86平台就是这
样定义的. 在这里大家要注意一个问题:由于参数的地址用于va_start宏,所以参数不能声明为寄存器变量或作为函数或数组类型.
关于va_start, va_arg, va_end的描述就是这些了,我们要注意的 是不同的操作系统和硬件平台的定义有些不同,但原理却是相似的.<br /><br />
(三)可变参数在编程中要注意的问题 <br />
因为va_start, va_arg, va_end等定义成宏,所以它显得很愚蠢,
可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能 地识别不同参数的个数和类型.
有人会问:那么printf中不是实现了智能识别参数吗?那是因为函数
printf是从固定参数format字符串来分析出参数的类型,再调用va_arg
的来获取可变参数的.也就是说,你想实现智能识别可变参数的话是要通过在自己的程序里作判断来实现的. 例如，在C的经典教材《the c
programming language》的7.3节中就给出了一个printf的可能实现方式，由于篇幅原因这里不再叙述。<br />
（四）小结: <br />
1、标准C库的中的三个宏的作用只是用来确定可变参数列表中每个参数的内存地址，编译器是不知道参数的实际数目的。<br />
2、在实际应用的代码中，程序员必须自己考虑确定参数数目的办法，如<br />
⑴在固定参数中设标志—— printf函数就是用这个办法。后面也有例子。<br />
⑵在预先设定一个特殊的结束标记，就是说多输入一个可变参数，调用时要将最后一个可变参数的值设置成这个特殊的值，在函数体中根据这个值判断是否达到参数的结尾。本文前面的代码就是采用这个办法.<br />
无论采用哪种办法，程序员都应该在文档中告诉调用者自己的约定。<br />
3、实现可变参数的要点就是想办法取得每个参数的地址，取得地址的办法由以下几个因素决定：<br />
①函数栈的生长方向<br />
②参数的入栈顺序<br />
③CPU的对齐方式<br />
④内存地址的表达方式<br />
结合源代码，我们可以看出va_list的实现是由④决定的，_INTSIZEOF(n)的引入则是由③决定的，他和①②又一起决定了va_start的实现，最后va_end的存在则是良好编程风格的体现，将不再使用的指针设为NULL,这样可以防止以后的误操作。<br />
4、取得地址后，再结合参数的类型，程序员就可以正确的处理参数了。理解了以上要点，相信稍有经验的读者就可以写出适合于自己机器的实现来。下面臼且桓隼?<br />
（五）扩展——自己实现简单的可变参数的函数。<br />
下面是一个简单的printf函数的实现，参考了&lt;The C Programming Language&gt;中的156页的例子，读者可以结合书上的代码与本文参照。<br />
#include "stdio.h"<br />
#include "stdlib.h"<br />
void myprintf(char* fmt, ...)        //一个简单的类似于printf的实现，//参数必须都是int 类型<br />
{ <br />
    char* pArg=NULL;               //等价于原来的va_list <br />
    char c;<br />
    <br />
    pArg = (char*) &amp;fmt;          //注意不要写成p = fmt !!因为这里要对//参数取址，而不是取值<br />
    pArg += sizeof(fmt);         //等价于原来的va_start          <br /><br />
    do<br />
    {<br />
        c =*fmt;<br />
        if (c != '%')<br />
        {<br />
            putchar(c);            //照原样输出字符<br />
        }<br />
        else<br />
{<br />
//按格式字符输出数据<br />
            switch(*++fmt) <br />
{<br />
            case 'd':<br />
                printf("%d",*((int*)pArg));           <br />
                break;<br />
            case 'x':<br />
                printf("%#x",*((int*)pArg));<br />
                break;<br />
            default:<br />
                break;<br />
            } <br />
            pArg += sizeof(int);               //等价于原来的va_arg<br />
        }<br />
        ++fmt;<br />
    }while (*fmt != '\0'); <br />
    pArg = NULL;                               //等价于va_end<br />
    return; <br />
}<br />
int main(int argc, char* argv[])<br />
{<br />
    int i = 1234;<br />
    int j = 5678;<br />
    <br />
    myprintf("the first test:i=%d",i,j); <br />
    myprintf("the secend test:i=%d; %x;j=%d;",i,0xabcd,j); <br />
    system("pause");<br />
    return 0;<br />
}<br />
在intel+win2k+vc6的机器执行结果如下：<br />
the first test:i=1234<br />
the secend test:i=1234; 0xabcd;j=5678;<br />
#include &lt;stdarg.h&gt;//不定数目参数需要的宏<br />
int max(int n,int num,...)<br />
{<br />
va_list x;//说明变量x<br />
va_start(x,num);//x被初始化为指向num后的第一个参数<br />
int m=num;<br />
for(int i=1;i&lt;n;i++)<br />
{<br />
//将变量x所指向的int类型的值赋给y,同时使x指向下一个参数<br />
int y=va_arg(x,int);<br />
if(y&gt;m)m=y;<br />
}<br />
va_end(x);//清除变量x<br />
return m;<br />
}<br />
main()<br />
{<br />
    printf("%d,%d",max(3,5,56),max(6,0,4,32,45,533));<br />
}<br /><br /><img src ="http://www.cppblog.com/lmlf001/aggbug/5874.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 13:28 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5874.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C预处理指令</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5873.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 05:14:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5873.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5873.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5873.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5873.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5873.html</trackback:ping><description><![CDATA[
		<span class="top11">原文地址：http://www.51cto.com/html/2005/0927/3844.htm<br /><br />一、预处理的由来：<br />在C++的历史发展中，有很多的语言特征（特别是语言的晦涩之处）来自于C语言，预处理就是其中的一个。C++从C语言那里把C语言预处理器继承过来（C语言预处理器，被Bjarne博士简称为Cpp，不知道是不是C Program Preprocessor的简称）。<br /><br />二、常见的预处理功能：<br />预处理器的主要作用就是把通过预处理的内建功能对一个资源进行等价替换，最常见的预处理有：文件包含，条件编译、布局控制和宏替换4种。<br />文件包含：#include 是一种最为常见的预处理，主要是做为文件的引用组合源程序正文。<br />条件编译：#if,#ifndef,#ifdef,#endif,#undef等也是比较常见的预处理，主要是进行编译时进行有选择的挑选，注释掉一些指定的代码，以达到版本控制、防止对文件重复包含的功能。<br />布局控制：#progma，这也是我们应用预处理的一个重要方面，主要功能是为编译程序提供非常规的控制流信息。<br />宏替换： #define，这是最常见的用法，它可以定义符号常量、函数功能、重新命名、字符串的拼接等各种功能。<br /><br />三、预处理指令：<br />预处理指令的格式如下：<br /># directive tokens<br />#符号应该是这一行的第一个非空字符，一般我们把它放在起始位置。如果指令一行放不下，可以通过\进行控制，例如：<br />#define Error if(error) exit(1) 等价于<br />#define Error \<br />if(error) exit(1)<br />不过我们为了美化起见，一般都不怎么这么用，更常见的方式如下：<br /># ifdef __BORLANDC__<br />if_true&lt;(is_convertible&lt;Value,named_template_param_base&gt;::value)&gt;::<br />template then&lt;make_named_arg, make_key_value&gt;::type Make;<br /># else<br />enum { is_named = is_named_parameter&lt;Value&gt;::value };<br />typedef typename if_true&lt;(is_named)&gt;::template<br />then&lt;make_named_arg, make_key_value&gt;::type Make;<br /># endif<br />下面我们看一下常见的预处理指令：<br />#define 宏定义<br />#undef 未定义宏<br />#include 文本包含<br />#ifdef 如果宏被定义就进行编译<br />#ifndef 如果宏未被定义就进行编译<br />#endif 结束编译块的控制<br />#if 表达式非零就对代码进行编译<br />#else 作为其他预处理的剩余选项进行编译<br />#elif 这是一种#else和#if的组合选项 <img style="vertical-align: middle;" alt="tongue.gif" src="http://www.s8s8.net/forums/html/emoticons/tongue.gif" border="0" /><br />#line 改变当前的行数和文件名称<br />#error 输出一个错误信息<br />#pragma 为编译程序提供非常规的控制流信息<br />下面我们对这些预处理进行一一的说明，考虑到宏的重要性和繁琐性，我们把它放到最后讲。<br /><br />四、文件包含指令：<br />这种预处理使用方式是最为常见的，平时我们编写程序都会用到，最常见的用法是：<br />#include &lt;iostream&gt;         //标准库头文件<br />#include &lt;iostream.h&gt;         //旧式的标准库头文件<br />#include "IO.h"             //用户自定义的头文件<br />#include "../file.h"         //UNIX下的父目录下的头文件<br />#include "/usr/local/file.h" //UNIX下的完整路径<br />#include "..\file.h"         //Dos下的父目录下的头文件<br />#include "\usr\local\file.h" //Dos下的完整路径<br />这里面有2个地方要注意：<br />1、我们用&lt;iostream&gt;还是&lt;iostream.h&gt;?<br />我们主张使用&lt;iostream&gt;，而不是&lt;iostream.h&gt;,为什么呢？我想你可能还记得我曾经给出过几点理由，这里我大致的说一下：首先，.h格式的头文件早在98年9月份就被标准委员会抛弃了，我们应该紧跟标准，以适合时代的发展。其次，iostream.h只支持窄字符集，iostream则支持窄/宽字符集。<br />还有，标准对iostream作了很多的改动，接口和实现都有了变化。最后，iostream组件全部放入namespace std中，防止了名字污染。<br />2、&lt;io.h&gt;和"io.h"的区别？<br />其实他们唯一的区别就是搜索路径不同：<br />对于#include &lt;io.h&gt; ，编译器从标准库路径开始搜索<br />对于#include "io.h" ，编译器从用户的工作路径开始搜索<br />五、编译控制指令：<br />这些指令的主要目的是进行编译时进行有选择的挑选，注释掉一些指定的代码，以达到版本控制、防止对文件重复包含的功能。<br />使用格式，如下：<br />1、<br />#ifdef identifier<br />your code<br />#endif<br />如果identifier为一个定义了的符号，your code就会被编译，否则剔除<br />2、<br />#ifndef identifier<br />your code<br />#endif<br />如果identifier为一个未定义的符号，your code就会被编译，否则剔除<br />3、<br />#if expression<br />your code<br />#endif<br />如果expression非零，your code就会被编译，否则剔除<br />4、<br />#ifdef identifier<br />your code1<br />#else<br />your code2<br />#endif<br />如果identifier为一个定义了的符号，your code1就会被编译，否则yourcode2就会被编译<br />5、<br />#if expressin1<br />your code1<br />#elif expression2 //呵呵，elif<br />your code2<br />#else<br />your code3<br />#enif<br />如果epression1非零，就编译your code1，否则，如果expression2非零，就编译your code2，否则，就编译your code3<br /><br />其他预编译指令<br />除了上面我们说的集中常用的编译指令，还有3种不太常见的编译指令：#line、#error、#pragma，我们接下来就简单的谈一下。<br />#line的语法如下：<br />#line number filename<br />例如：#line 30 a.h 其中，文件名a.h可以省略不写。<br />这条指令可以改变当前的行号和文件名，例如上面的这条预处理指令就可以改变当前的行号为30，文件名是a.h。初看起来似乎没有什么用，不过，他还是有点用的，那就是用在编译器的编写中，我们知道编译器对C++源码编译过程中会产生一些中间文件，通过这条指令，可以保证文件名是固定的，不会被这些中间文件代替，有利于进行分析。<br />#error语法如下：<br />#error info<br />例如：#ifndef UNIX<br />#error This software requires the UNIX OS.<br />#endif<br />这条指令主要是给出错误信息，上面的这个例子就是，如果没有在UNIX环境下，就会输出This software requires the UNIX OS.然后诱发编译器终止。所以总的来说，这条指令的目的就是在程序崩溃之前能够给出一定的信息。<br />#pragma是非统一的，他要依靠各个编译器生产者，例如，在SUN C++编译器中：<br />// 把name和val的起始地址调整为8个字节的倍数<br />#progma align 8 (name, val)<br />char name[9];<br />double val;<br />//在程序执行开始，调用函数MyFunction<br />#progma init (MyFunction)<br />预定义标识符<br />为了处理一些有用的信息，预处理定义了一些预处理标识符，虽然各种编译器的预处理标识符不尽相同，但是他们都会处理下面的4种：<br />__FILE__ 正在编译的文件的名字<br />__LINE__ 正在编译的文件的行号<br />__DATE__ 编译时刻的日期字符串，例如： "25 Dec 2000"<br />__TIME__ 编译时刻的时间字符串，例如： "12:30:55"<br />例如：cout&lt;&lt;"The file is :"&lt;&lt;__FILE__"&lt;&lt;"! The lines is:"&lt;&lt;__LINE__&lt;&lt;endl;<br /><br />预处理何去何从<br />如何取代#include预处理指令，我们在这里就不再一一讨论了。<br />C++并没有为#include提供替代形式，但是namespace提供了一种作用域机制，它能以某种方式支持组合，利用它可以改善#include的行为方式，但是我们还是无法取代#include。<br />#progma应该算是一个可有可无的预处理指令，按照C++之父Bjarne的话说，就是："#progma被过分的经常的用于将语言语义的变形隐藏到编译系统里，或者被用于提供带有特殊语义和笨拙语法的语言扩充。”<br />对于#ifdef，我们仍然束手无策，就算是我们利用if语句和常量表达式，仍然不足以替代她，因为一个if语句的正文必须在语法上正确，满足类检查，即使他处在一个绝不会被执行的分支里面。 </span>
<img src ="http://www.cppblog.com/lmlf001/aggbug/5873.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 13:14 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5873.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符串处理库中的内存函数</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5872.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 05:00:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5872.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5872.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5872.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5872.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5872.html</trackback:ping><description><![CDATA[#include&lt;string.h&gt;<br /><br /><table id="table1" border="1" width="100%"><tbody><tr><td>函数原型</td><td>函数描述</td></tr><tr><td><span style="font-family: Verdana;" lang="EN-US"><font size="2">void 
		*memcpy(void *s1,const void *s2, size_t n)</font></span></td><td><span style="font-family: 宋体;">把</span><span style="font-family: Verdana;" lang="EN-US">s2</span><span style="font-family: 宋体;">所指的对象中的</span><span style="font-family: Verdana;" lang="EN-US">n</span><span style="font-family: 宋体;">个字符复制到</span><span style="font-family: Verdana;" lang="EN-US">s1</span><span style="font-family: 宋体;">所指的对象中。返回</span><span style="font-family: Verdana;" lang="EN-US">s1</span><span style="font-family: 宋体;">结果指针</span></td></tr><tr><td><span style="font-family: Verdana;" lang="EN-US"><font size="2">void 
		*memmove(void *s1,const void *s2,size_t n)</font></span></td><td><span style="font-family: 宋体;">同</span><span style="font-family: Verdana;" lang="EN-US">memcpy,</span><span style="font-family: 宋体;">并且多考虑了重叠情况（</span><span style="font-family: Verdana;" lang="EN-US">Overlapping 
		Buffers</span><span style="font-family: 宋体;">）</span></td></tr><tr><td><span style="font-family: Verdana;" lang="EN-US"><font size="2">int 
		memcmp(const void *s1,const void *s2,size_t n)</font></span></td><td><p class="MsoNormal"><span style="font-family: Verdana;" lang="EN-US">s1</span><span style="font-family: 宋体;">和</span><span style="font-family: Verdana;" lang="EN-US">s2</span><span style="font-family: 宋体;">指向对象的前</span><span style="font-family: Verdana;" lang="EN-US">n</span><span style="font-family: 宋体;">个字符。如果</span><span style="font-family: Verdana;" lang="EN-US">s1</span><span style="font-family: 宋体;">所指向对象的字符等于、小于或大于</span><span style="font-family: Verdana;" lang="EN-US">s2</span><span style="font-family: 宋体;">所指向对象中的字符，返回值分别等于</span><span style="font-family: Verdana;" lang="EN-US">0</span><span style="font-family: 宋体;">、</span><span style="font-family: Verdana;" lang="EN-US">&lt;0
		</span><span style="font-family: 宋体;">、</span><span style="font-family: Verdana;" lang="EN-US">&gt;0</span></p></td></tr><tr><td><span style="font-family: Verdana;" lang="EN-US"><font size="2">void 
		*memchr(const char *s,int c,size_t n)</font></span></td><td><span style="font-family: 宋体;">定位</span><span style="font-family: Verdana;" lang="EN-US">s</span><span style="font-family: 宋体;">的前</span><span style="font-family: Verdana;" lang="EN-US">n</span><span style="font-family: 宋体;">个字符首次出现</span><span style="font-family: Verdana;" lang="EN-US">c</span><span style="font-family: 宋体;">的位置。找到就返回指向它的指针，否则返回</span><span style="font-family: Verdana;" lang="EN-US">0</span></td></tr><tr><td><span style="font-family: Verdana;" lang="EN-US"><font size="2">void 
		*memset(void *s, int c,size_t n)</font></span></td><td><span style="font-family: 宋体;">把</span><span style="font-family: Verdana;" lang="EN-US">c</span><span style="font-family: 宋体;">复制到</span><span style="font-family: Verdana;" lang="EN-US">s</span><span style="font-family: 宋体;">所指的对象的前</span><span style="font-family: Verdana;" lang="EN-US">n</span><span style="font-family: 宋体;">个字符中。返回指向结果指针</span></td></tr></tbody></table><img src ="http://www.cppblog.com/lmlf001/aggbug/5872.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 13:00 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5872.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符串处理库中的查找函数</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5871.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 04:57:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5871.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5871.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5871.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5871.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5871.html</trackback:ping><description><![CDATA[#include&lt;string.h&gt;<br /><br /><table id="table1" border="1" width="100%"><tbody><tr><td>函数原型</td><td>函数描述</td></tr><tr><td><font size="2"><span style="font-family: Verdana;" lang="EN-US">char *strchr(const 
		char *s,int c)</span></font></td><td><span style="font-family: 宋体;">查找</span><span style="font-family: Verdana;" lang="EN-US">c</span><span style="font-family: 宋体;">在</span><span style="font-family: Verdana;" lang="EN-US">s</span><span style="font-family: 宋体;">中首次出现的位置，成功将返回该位置的指针，否则返回</span><span style="font-family: Verdana;" lang="EN-US">NULL</span></td></tr><tr><td><font size="2"><span style="font-family: Verdana;" lang="EN-US">size_t 
		strcspn(const char *s1,const char *s2)</span></font></td><td><span style="font-family: 宋体;">计算并返回</span><span style="font-family: Verdana;" lang="EN-US">s1</span><span style="font-family: 宋体;">中不包含</span><span style="font-family: Verdana;" lang="EN-US">s2</span><span style="font-family: 宋体;">中任何字符的起始段的长度。即在</span><span style="font-family: Verdana;" lang="EN-US">s1</span><span style="font-family: 宋体;">中查找是否有</span><span style="font-family: Verdana;" lang="EN-US">s2</span><span style="font-family: 宋体;">的字符，若碰到有该字符则返回从开始（数数</span><span style="font-family: Verdana;" lang="EN-US">1</span><span style="font-family: 宋体;">开始）到该字符之前的字符串长度。</span></td></tr><tr><td><p class="MsoNormal"><font size="2"><span style="font-family: Verdana;" lang="EN-US">
		size_t strspn(const char *s1,const char *s2)</span></font></p></td><td><span style="font-family: 宋体;">计算并返回</span><span style="font-family: Verdana;" lang="EN-US">s1</span><span style="font-family: 宋体;">中只包含</span><span style="font-family: Verdana;" lang="EN-US">s2</span><span style="font-family: 宋体;">中字符的起始段长度。即当在</span><span style="font-family: Verdana;" lang="EN-US">s1</span><span style="font-family: 宋体;">中没遇到在</span><span style="font-family: Verdana;" lang="EN-US">s2</span><span style="font-family: 宋体;">中的字符时，返回从开始到该字符之前的字符串的长度。</span></td></tr><tr><td><font size="2"><span style="font-family: Verdana;" lang="EN-US">char *strpbrk(const 
		char *s1,const char *s2)</span></font></td><td><span style="font-family: 宋体;">定位字符串</span><span style="font-family: Verdana;" lang="EN-US">s1</span><span style="font-family: 宋体;">首次出现在字符串</span><span style="font-family: Verdana;" lang="EN-US">s2</span><span style="font-family: 宋体;">中字符的位置。若找到了字符串</span><span style="font-family: Verdana;" lang="EN-US">s2</span><span style="font-family: 宋体;">中的字符，返回一个指向字符串</span><span style="font-family: Verdana;" lang="EN-US">s1</span><span style="font-family: 宋体;">中该字符的指针，否则返回</span><span style="font-family: Verdana;" lang="EN-US">NULL</span></td></tr><tr><td><font size="2"><span style="font-family: Verdana;" lang="EN-US">char *strrchr(const 
		char *s,int c)</span></font></td><td><span style="font-family: 宋体;">返回</span><span style="font-family: Verdana;" lang="EN-US">c</span><span style="font-family: 宋体;">在</span><span style="font-family: Verdana;" lang="EN-US">s</span><span style="font-family: 宋体;">中最后一次出现的位置指针，否则返回</span><span style="font-family: Verdana;" lang="EN-US">NULL</span></td></tr><tr><td><p class="MsoNormal"><font size="2"><span style="font-family: Verdana;" lang="EN-US">
		char *strstr(const char *s1, const char *s2)</span></font></p></td><td><span style="font-family: 宋体;">返回</span><span style="font-family: Verdana;" lang="EN-US">s2</span><span style="font-family: 宋体;">在</span><span style="font-family: Verdana;" lang="EN-US">s1</span><span style="font-family: 宋体;">中首次出现（整个字符串匹配）的位置指针，否则返回</span><span style="font-family: Verdana;" lang="EN-US">NULL</span></td></tr></tbody></table><img src ="http://www.cppblog.com/lmlf001/aggbug/5871.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 12:57 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5871.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符串与数字之间的转换函数</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5870.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 04:50:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5870.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5870.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5870.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5870.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5870.html</trackback:ping><description><![CDATA[#include&lt;stdlib.h&gt;<br /><br /><div align="center"><table id="table1" border="1" height="138" width="100%"><tbody><tr><td><font size="2">函数原型</font></td><td>函数描述</td></tr><tr><td><font size="2"><span lang="EN-US">double atof(const char *nPtr)<span style=""> </span></span></font></td><td>把字符串<span lang="EN-US">nPtr</span>转换为<span lang="EN-US">double</span>类型</td></tr><tr><td><font size="2"><span lang="EN-US">int atoi(const char* nPtr)<span style=""> </span></span></font></td><td>把字符串<span lang="EN-US">nPtr</span>转换为<span lang="EN-US">int</span>类型</td></tr><tr><td><font size="2">long atol(const char *nPtr)</font></td><td><p class="MsoNormal">把字符串<span lang="EN-US">nPtr</span>转换为<span lang="EN-US">long</span></p></td></tr><tr><td><font size="2"><span lang="EN-US">double strtod(const char* nPtr,char **endPtr)</span></font></td><td>把字符串<span lang="EN-US">nPtr</span>转换为<span lang="EN-US">double</span>类型，<span lang="EN-US">endPtr指向nPtr中第一个不是数字的字符的位置</span></td></tr><tr><td><font size="2"><span lang="EN-US">long strtol(const char *nPtr,char** endPtr, 
			int base)</span></font></td><td>把字符串<span lang="EN-US">nPtr</span>转换为<span lang="EN-US">long</span>类型，<span lang="EN-US">eendPtr指向nPtr中第一个不是数字的字符的位置</span>，<span lang="EN-US">base</span>是待转换字符串中数值的进制类型，<span lang="EN-US">0</span>表示可以是（<span lang="EN-US">8</span>、<span lang="EN-US">10</span>、<span lang="EN-US">16</span>）。也可是<span lang="EN-US">2</span>～<span lang="EN-US">36</span>中任何值。</td></tr><tr><td><p class="MsoNormal"><font size="2"><span lang="EN-US">unsigned long strtoul(const 
			char* nPtr,char **endPtr, int base)</span></font></p><br /></td><td>把字符串<span lang="EN-US">nPtr</span>转换为<span lang="EN-US">unsigned 
			long</span>类型，<span lang="EN-US">endPtr指向nPtr中第一个不是数字的字符的位置</span>，<span lang="EN-US">base</span>是待转换字符串中数值的进制类型，<span lang="EN-US">0</span>表示可以是（<span lang="EN-US">8</span>、<span lang="EN-US">10</span>、<span lang="EN-US">16</span>）。也可是<span lang="EN-US">2</span>～<span lang="EN-US">36</span>中任何值。</td></tr></tbody></table></div><br /><img src ="http://www.cppblog.com/lmlf001/aggbug/5870.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 12:50 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5870.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C字符处理函数库</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/19/5868.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Wed, 19 Apr 2006 04:28:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/19/5868.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5868.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/19/5868.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5868.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5868.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal">
				<span style="font-family: Verdana;" lang="EN-US">#include&lt;ctype.h&gt;<br /></span>
		</p>
		<br />
		<table style="width: 558px; height: 506px;" id="table1" border="1">
				<tbody>
						<tr>
								<td width="152">函数原型</td>
								<td>
										<font face="Book Antiqua">函数描述</font>
								</td>
						</tr>
						<tr>
								<td width="152">
										<span lang="EN-US">int isdigit(int c)</span>
								</td>
								<td>
										<span style="font-family: Book Antiqua;">如果</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">c</span>
										<span style="font-family: Book Antiqua;">是一个数字，返回</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">true</span>
										<span style="font-family: Book Antiqua;">，否则返回</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">false</span>
								</td>
						</tr>
						<tr>
								<td width="152">
										<span lang="EN-US">int isalpha(int c)</span>
								</td>
								<td>
										<span style="font-family: Book Antiqua;">如果</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">c</span>
										<span style="font-family: Book Antiqua;">是一个字母，返回</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">true</span>
										<span style="font-family: Book Antiqua;">，否则返回</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">false</span>
								</td>
						</tr>
						<tr>
								<td width="152">
										<span lang="EN-US">int isalnum(int c)</span>
								</td>
								<td>
										<span style="font-family: Book Antiqua;">如果</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">c</span>
										<span style="font-family: Book Antiqua;">是一个字母或数字，返回</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">true</span>
										<span style="font-family: Book Antiqua;">，否则返回</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">false</span>
								</td>
						</tr>
						<tr>
								<td width="152">
										<span lang="EN-US">int isxdigit(int c)</span>
								</td>
								<td>
										<p class="MsoNormal">
												<span style="font-family: Book Antiqua;">如果</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">c</span>
												<span style="font-family: Book Antiqua;">是一个十六进制字符，返回</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">true</span>
												<span style="font-family: Book Antiqua;">，否则返回</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">false</span>
										</p>
								</td>
						</tr>
						<tr>
								<td width="152">
										<span lang="EN-US">int islower(int c)</span>
								</td>
								<td>
										<span style="font-family: Book Antiqua;">如果</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">c</span>
										<span style="font-family: Book Antiqua;">是一个小写字母，返回</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">true</span>
										<span style="font-family: Book Antiqua;">，否则返回</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">false</span>
								</td>
						</tr>
						<tr>
								<td width="152">
										<span lang="EN-US">int isupper(int c) </span>
								</td>
								<td>
										<p class="MsoNormal">
												<span style="font-family: Book Antiqua;">如果</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">c</span>
												<span style="font-family: Book Antiqua;">是一个大写字母，返回</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">true</span>
												<span style="font-family: Book Antiqua;">，否则返回</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">false</span>
										</p>
								</td>
						</tr>
						<tr>
								<td width="152">
										<span lang="EN-US">int tolower(int c)</span>
								</td>
								<td>
										<p class="MsoNormal">
												<span style="font-family: Book Antiqua;">
		如果c为大写字母，返回其小写字母，否则返回原参数</span>
										</p>
								</td>
						</tr>
						<tr>
								<td width="152">
										<p class="MsoNormal">
												<span lang="EN-US">int toupper(int c)</span>
										</p>
								</td>
								<td>
										<p class="MsoNormal">
												<span style="font-family: Book Antiqua;" lang="EN-US">如果c为小写字母，</span>
												<span style="font-family: Book Antiqua;">返回其大写字母，否则返回原参数</span>
										</p>
								</td>
						</tr>
						<tr>
								<td width="152">
										<span lang="EN-US">int isspace(int c) </span>
								</td>
								<td>
										<span style="font-family: Book Antiqua;">如果</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">c</span>
										<span style="font-family: Book Antiqua;">是一个空白符，返回</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">true</span>
										<span style="font-family: Book Antiqua;">，否则返回</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">false</span>
										<span style="font-family: Book Antiqua;">。空白符包括：</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">’\n’,
		</span>
										<span style="font-family: Book Antiqua;">空格，</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">’\t’ 
		, ‘\r’ ,</span>
										<span style="font-family: Book Antiqua;">进纸符（</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">’\f’</span>
										<span style="font-family: Book Antiqua;">）</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">,</span>
										<span style="font-family: Book Antiqua;">垂直制表符</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">(‘\v’)</span>
								</td>
						</tr>
						<tr>
								<td width="152">
										<span lang="EN-US">int iscntrl(int c)</span>
								</td>
								<td>
										<span style="font-family: Book Antiqua;" lang="EN-US">
										</span>
										<span style="font-family: Book Antiqua;">如果</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">c</span>
										<span style="font-family: Book Antiqua;">是一个控制符，返回</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">true</span>
										<span style="font-family: Book Antiqua;">，否则返回</span>
										<span style="font-family: Book Antiqua;" lang="EN-US">false</span>
								</td>
						</tr>
						<tr>
								<td width="152">
										<span lang="EN-US">int ispunct(int c)</span>
								</td>
								<td>
										<p class="MsoNormal">
												<span style="font-family: Book Antiqua;" lang="EN-US">
												</span>
												<span style="font-family: Book Antiqua;">如果</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">c</span>
												<span style="font-family: Book Antiqua;">是一个除空格、数字和字母外的可打印字符，返回</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">true</span>,<span style="font-family: Book Antiqua;">否则返回</span><span style="font-family: Book Antiqua;" lang="EN-US">false</span></p>
								</td>
						</tr>
						<tr>
								<td width="152">
										<span lang="EN-US">int isprint(int c) </span>
								</td>
								<td>
										<p class="MsoNormal">
												<span style="font-family: Book Antiqua;">如果</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">c</span>
												<span style="font-family: Book Antiqua;">是一个可打印符（包括空格），返回</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">true</span>
												<span style="font-family: Book Antiqua;">，否则返回</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">false</span>
										</p>
								</td>
						</tr>
						<tr>
								<td width="152">
										<span lang="EN-US">int isgraph(int c)</span>
								</td>
								<td>
										<p class="MsoNormal">
												<span style="font-family: Book Antiqua;" lang="EN-US">
												</span>
												<span style="font-family: Book Antiqua;">如果</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">c</span>
												<span style="font-family: Book Antiqua;">是除空格之外的可打印字符，返回</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">true</span>
												<span style="font-family: Book Antiqua;">，否则返回</span>
												<span style="font-family: Book Antiqua;" lang="EN-US">false</span>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/lmlf001/aggbug/5868.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-19 12:28 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/19/5868.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++文件操作</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/18/5815.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Tue, 18 Apr 2006 05:03:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/18/5815.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5815.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/18/5815.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5815.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5815.html</trackback:ping><description><![CDATA[ 原文地址：http://www.layz.net/blog/user1/xuanxuan/archives/2006/67.html<br /> 在C++中，有一个stream这个类，所有的I/O都以这个“流”类为基础的，包括我们要认识的文件I/O，stream这个类有两个重要的运算符： <br /><br />1、插入器(&lt;&lt;) <br />　
　向流输出数据。比如说系统有一个默认的标准输出流(cout)，一般情况下就是指的显示器，所以，cout&lt;&lt;"Write
Stdout"&lt;&lt;'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。 <br /><br />2、析取器(&gt;&gt;) <br />　　从流中输入数据。比如说系统有一个默认的标准输入流(cin)，一般情况下就是指的键盘，所以，cin&gt;&gt;x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。 <br /><br />　　在C++中，对文件的操作是通过stream的子类fstream(file stream)来实现的，所以，要用这种方式操作文件，就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。 <br /><br />一、打开文件 <br />　　在fstream类中，有一个成员函数open()，就是用来打开文件的，其原型是： <br /><br />void open(const char* filename,int mode,int access); <br /><br />参数： <br /><br />filename：　　要打开的文件名 <br />mode：　　　　要打开文件的方式 <br />access：　　　打开文件的属性 <br />打开文件的方式在类ios(是所有流式I/O类的基类)中定义，常用的值如下： <br /><br />ios::app：　　　以追加的方式打开文件 <br />ios::ate：　　　文件打开后定位到文件尾，ios:app就包含有此属性 <br />ios::binary： 　以二进制方式打开文件，缺省的方式是文本方式。两种方式的区别见前文 <br />ios::in：　　　 文件以输入方式打开 <br />ios::out：　　　文件以输出方式打开 <br />ios::nocreate： 不建立文件，所以文件不存在时打开失败　 <br />ios::noreplace：不覆盖文件，所以打开文件时如果文件存在失败 <br />ios::trunc：　　如果文件存在，把文件长度设为0 <br />　　可以用“或”把以上属性连接起来，如ios::out|ios::binary <br /><br />　　打开文件的属性取值是： <br /><br />0：普通文件，打开访问 <br />1：只读文件 <br />2：隐含文件 <br />4：系统文件 <br />　　可以用“或”或者“+”把以上属性连接起来 ，如3或1|2就是以只读和隐含属性打开文件。 <br /><br />　　例如：以二进制输入方式打开文件c:\config.sys <br /><br />　　fstream file1; <br />　　file1.open("c:\\config.sys",ios::binary|ios::in,0); <br /><br />　　如果open函数只有文件名一个参数，则是以读/写普通文件打开，即： <br /><br />　　file1.open("c:\\config.sys");&lt;=&gt;file1.open("c:\\config.sys",ios::in|ios::out,0); <br /><br />　　另外，fstream还有和open()一样的构造函数，对于上例，在定义的时侯就可以打开文件了： <br /><br />　　fstream file1("c:\\config.sys"); <br /><br />　　特别提出的是，fstream有两个子类：ifstream(input file stream)和ofstream(outpu file stream)，ifstream默认以输入方式打开文件，而ofstream默认以输出方式打开文件。 <br /><br />　　ifstream file2("c:\\pdos.def");//以输入方式打开文件 <br />　　ofstream file3("c:\\x.123");//以输出方式打开文件 <br /><br />　　所以，在实际应用中，根据需要的不同，选择不同的类来定义：如果想以输入方式打开，就用ifstream来定义；如果想以输出方式打开，就用ofstream来定义；如果想以输入/输出方式来打开，就用fstream来定义。 <br /><br />二、关闭文件 <br />　　打开的文件使用完成后一定要关闭，fstream提供了成员函数close()来完成此操作，如：file1.close();就把file1相连的文件关闭。 <br /><br />三、读写文件 <br />　　读写文件分为文本文件和二进制文件的读取，对于文本文件的读取比较简单，用插入器和析取器就可以了；而对于二进制的读取就要复杂些，下要就详细的介绍这两种方式 <br /><br />　　1、文本文件的读写 <br />　　文本文件的读写很简单：用插入器(&lt;&lt;)向文件输出；用析取器(&gt;&gt;)从文件输入。假设file1是以输入方式打开，file2以输出打开。示例如下： <br /><br />　　file2&lt;&lt;"I Love You";//向文件写入字符串"I Love You" <br />　　int i; <br />　　file1&gt;&gt;i;//从文件输入一个整数值。 <br /><br />　　这种方式还有一种简单的格式化能力，比如可以指定输出为16进制等等，具体的格式有以下一些 <br /><br />操纵符 功能 输入/输出 <br />dec 格式化为十进制数值数据 输入和输出 <br />endl 输出一个换行符并刷新此流 输出 <br />ends 输出一个空字符 输出 <br />hex 格式化为十六进制数值数据 输入和输出 <br />oct 格式化为八进制数值数据 输入和输出 <br />setpxecision(int p) 设置浮点数的精度位数 输出 <br /><br />　　比如要把123当作十六进制输出：file1&lt;&lt;&lt;123;要把3.1415926以5位精度输出：FILE1&lt;<setpxecision(5)>&lt;&lt;3.1415926。 <br /><br />　　2、二进制文件的读写 <br />①put() <br />　　put()函数向流写入一个字符，其原型是ofstream &amp;put(char ch)，使用也比较简单，如file1.put('c');就是向流写一个字符'c'。 <br /><br />②get() <br />　　get()函数比较灵活，有3种常用的重载形式： <br /><br />　　一种就是和put()对应的形式：ifstream &amp;get(char &amp;ch);功能是从流中读取一个字符，结果保存在引用ch中，如果到文件尾，返回空字符。如file2.get(x);表示从文件中读取一个字符，并把读取的字符保存在x中。 <br /><br />　　另一种重载形式的原型是： int get();这种形式是从流中返回一个字符，如果到达文件尾，返回EOF，如x=file2.get();和上例功能是一样的。 <br /><br />　
　还有一种形式的原型是：ifstream &amp;get(char *buf,int num,char
delim='\n')；这种形式把字符读入由 buf 指向的数组，直到读入了 num 个字符或遇到了由 delim 指定的字符，如果没使用
delim 这个参数，将使用缺省值换行符'\n'。例如： <br /><br />　　file2.get(str1,127,'A');//从文件中读取字符到字符串str1，当遇到字符'A'或读取了127个字符时终止。 <br /><br />③读写数据块 <br />　　要读写二进制数据块，使用成员函数read()和write()成员函数，它们原型如下： <br /><br />　　　　read(unsigned char *buf,int num); <br />　　　　write(const unsigned char *buf,int num); <br /><br />　
　read()从文件中读取 num 个字符到 buf 指向的缓存中，如果在还未读入 num 个字符时就到了文件尾，可以用成员函数 int
gcount();来取得实际读取的字符数；而 write() 从buf 指向的缓存写 num 个字符到文件中，值得注意的是缓存的类型是
unsigned char *，有时可能需要类型转换。 <br /><br />例： <br /><br />　　　　unsigned char str1[]="I Love You"; <br />　　　　int n[5]; <br />　　　　ifstream in("xxx.xxx"); <br />　　　　ofstream out("yyy.yyy"); <br />　　　　out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中 <br />　　　　in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数，注意类型转换 <br />　　　　in.close();out.close(); <br /><br />四、检测EOF <br />　　成员函数eof()用来检测是否到达文件尾，如果到达文件尾返回非0值，否则返回0。原型是int eof(); <br /><br />例：　　if(in.eof())ShowMessage("已经到达文件尾！"); <br /><br />五、文件定位 <br />　
　和C的文件操作方式不同的是，C++
I/O系统管理两个与一个文件相联系的指针。一个是读指针，它说明输入操作在文件中的位置；另一个是写指针，它下次写操作的位置。每次执行输入或输出时，
相应的指针自动变化。所以，C++的文件定位分为读位置和写位置的定位，对应的成员函数是 seekg()和
seekp()，seekg()是设置读位置，seekp是设置写位置。它们最通用的形式如下： <br /><br />　　　　istream &amp;seekg(streamoff offset,seek_dir origin); <br />　　　　ostream &amp;seekp(streamoff offset,seek_dir origin); <br /><br />　　streamoff定义于 iostream.h 中，定义有偏移量 offset 所能取得的最大值，seek_dir 表示移动的基准位置，是一个有以下值的枚举： <br /><br />ios::beg：　　文件开头 <br />ios::cur：　　文件当前位置 <br />ios::end：　　文件结尾 <br />　　这两个函数一般用于二进制文件，因为文本文件会因为系统对字符的解释而可能与预想的值不同。 <br /><br />例： <br /><br />　　　　 file1.seekg(1234,ios::cur);//把文件的读指针从当前位置向后移1234个字节 <br />　　　　 file2.seekp(1234,ios::beg);//把文件的写指针从文件开头向后移1234个字节<br /><br /><br /></setpxecision(5)><img src ="http://www.cppblog.com/lmlf001/aggbug/5815.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-18 13:03 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/18/5815.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++I/O操作</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/17/5761.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Mon, 17 Apr 2006 08:15:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/17/5761.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5761.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/17/5761.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5761.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5761.html</trackback:ping><description><![CDATA[
		<p language="Javascript1.2" id="fpAnimelasticRightFP10" style="left: 0px; visibility: visible; position: relative ! important; top: 0px;" endtop="0" endleft="0" inittop="0" initleft="802" startl="10" dynamicanimation="fpAnimelasticRightFP10">
				<b>
						<font face="宋体" size="2">原文地址:http://wonderow.cnblogs.com/archive/2005/06/21/178719.html<br /></font>
				</b>
		</p>
		<p language="Javascript1.2" id="fpAnimelasticRightFP10" style="left: 0px; visibility: visible; position: relative ! important; top: 0px;" endtop="0" endleft="0" inittop="0" initleft="802" startl="10" dynamicanimation="fpAnimelasticRightFP10">
				<b>
						<font face="宋体" size="2">格式控制</font>
						<a name="74">
						</a>
				</b>
				<font face="宋体" size="2">
				</font>
		</p>
		<p>
				<font face="宋体" size="2">    </font>
				<font color="#000011">
						<font face="宋体" size="2">在前面，输入／输出的数据没有指定格式，它们都按缺省的格式输入／输出。然而，有时需要对数据</font>
						<font face="宋体" size="2">格式进行控制。这时需利用ios类中定义的格式控制成员函数，通过调用它们来完成格式的设置。ios类的格式控制函数如下所示：<br /></font>
				</font>
		</p>
		<div align="left">
				<table border="1" cellpadding="0" width="545">
						<tbody>
								<tr>
										<td width="260">
												<font color="#ee0000" face="宋体" size="2">long flags( ) const</font>
										</td>
										<td width="275">
												<font color="#ee0000">
														<font color="#000011" face="宋体" size="2">返回当前的格式标志。</font>
												</font>
										</td>
								</tr>
								<tr>
										<td width="260">
												<font color="#ee0000" face="宋体" size="2">long flays(long newflag)</font>
										</td>
										<td width="275">
												<font color="#ee0000">
														<font color="#000011" face="宋体" size="2">设置格式标志为newflag，返回旧的格式标志。</font>
												</font>
										</td>
								</tr>
								<tr>
										<td width="260">
												<font color="#ee0000" face="宋体" size="2">long setf(long bits)   </font>
										</td>
										<td width="275">
												<font color="#ee0000">
														<font size="2">
																<font face="宋体">
																		<font color="#000011">设置指定的格式标志位，返回旧的格式标志。</font>
																</font>
														</font>
												</font>
										</td>
								</tr>
								<tr>
										<td width="260">
												<font color="#ee0000" face="宋体" size="2">long setf(long bits,long field)</font>
										</td>
										<td width="275">
												<font color="#ee0000">
														<font color="#000011" face="宋体" size="2">将field指定的格式标志位置为bits，返回旧的格式标志。</font>
												</font>
										</td>
								</tr>
								<tr>
										<td width="260">
												<font color="#ee0000" face="宋体" size="2">long unsetf(long bits) </font>
										</td>
										<td width="275">
												<font color="#ee0000">
														<font color="#000011" face="宋体" size="2">清除bits指定的格式标志位，返回旧的格式标志。</font>
												</font>
										</td>
								</tr>
								<tr>
										<td width="260">
												<font color="#ee0000" face="宋体" size="2">long fill(char c)  </font>
										</td>
										<td width="275">
												<font color="#ee0000">
														<font color="#000011" face="宋体" size="2">设置填充字符，缺省条件下是空格。</font>
												</font>
										</td>
								</tr>
								<tr>
										<td width="260">
												<font color="#ee0000" face="宋体" size="2">char fill( )  </font>
										</td>
										<td width="275">
												<font color="#ee0000">
														<font size="2">
																<font face="宋体"> <font color="#000011">返回当前填充字符。</font></font>
														</font>
												</font>
										</td>
								</tr>
								<tr>
										<td width="260">
												<font color="#ee0000" face="宋体" size="2">int precision(int val)  </font>
										</td>
										<td width="275">
												<font color="#ee0000">
														<font color="#000011" face="宋体" size="2">设置精确度为val，控制输出浮点数的有效位，返回旧值。</font>
												</font>
										</td>
								</tr>
								<tr>
										<td width="260">
												<font color="#ee0000" face="宋体" size="2">int precision( )</font>
										</td>
										<td width="275">
												<font color="#ee0000">
														<font color="#000011" face="宋体" size="2">返回旧的精确度值。</font>
												</font>
										</td>
								</tr>
								<tr>
										<td width="260">
												<font color="#ee0000" face="宋体" size="2">int width(int val)      </font>
										</td>
										<td width="275">
												<font color="#ee0000">
														<font color="#000011" face="宋体" size="2">设置显示数据的宽度(域宽),返回旧的域宽。</font>
												</font>
										</td>
								</tr>
								<tr>
										<td width="260">
												<font color="#ee0000" face="宋体" size="2">int width( )  </font>
										</td>
										<td width="275">
												<font size="2">
														<font face="宋体">
																<font color="#ee0000">
																		<font color="#000011">只返回当前域宽，缺省宽度为0。这时插入操作能按表示数</font>
																</font>
																<font color="#ee0000">
																		<font color="#000000">据的最小宽度显示数据。 </font>
																</font>
														</font>
												</font>
										</td>
								</tr>
						</tbody>
				</table>
		</div>
		<p>
				<font face="宋体">
						<font size="2">
								<font color="#ff00ff">预定义的操纵算子<br /></font>  <font color="#000011">  使用成员函数控制格式化输入输出时，每个函数调用需要写一条语句，尤其是它不能用在插入或提取运算符的表达式中，而使用操纵算子，则可以在插入和提取运算符的表达式中控制格式化输</font></font>
						<font color="#000011" size="2">入和输出。在程序中使用操纵算字必须嵌入头文件</font>
				</font>
				<font color="#0066ff" face="宋体" size="2">iomanip.h<br /></font>
		</p>
		<div align="left">
				<div align="left">
				</div>
				<table border="1" cellpadding="0" width="545">
						<tbody>
								<tr>
										<td align="left" width="262">
												<font color="#ee0000" face="宋体" size="2">dec</font>
										</td>
										<td width="273">
												<font color="#000011" face="宋体" size="2">十进制的输入输出</font>
										</td>
								</tr>
								<tr>
										<td align="left" width="262">
												<font color="#ee0000" face="宋体" size="2">hex</font>
										</td>
										<td width="273">
												<font size="2">
														<font face="宋体">
																<font color="#000011">十六进制的输入输出</font>
														</font>
												</font>
										</td>
								</tr>
								<tr>
										<td align="left" width="262">
												<font color="#ee0000" face="宋体" size="2">oct  </font>
										</td>
										<td width="273">
												<font color="#000011" face="宋体" size="2">八进制的输入输出</font>
										</td>
								</tr>
								<tr>
										<td align="left" width="262">
												<font color="#ee0000" face="宋体" size="2">ws  </font>
										</td>
										<td width="273">
												<font color="#000011" face="宋体" size="2">提取空白字符</font>
										</td>
								</tr>
								<tr>
										<td align="left" width="262">
												<font color="#ee0000" face="宋体" size="2">ends  </font>
										</td>
										<td width="273">
												<font color="#000011" face="宋体" size="2">输出一个nul字符</font>
										</td>
								</tr>
								<tr>
										<td align="left" width="262">
												<font color="#ee0000" face="宋体" size="2">endl </font>
										</td>
										<td width="273">
												<font size="2">
														<font face="宋体">
																<font color="#ee0000"> </font>
																<font color="#000011">输出一个换行字符，同时刷新流</font>
														</font>
												</font>
										</td>
								</tr>
								<tr>
										<td align="left" width="262">
												<font color="#ee0000" face="宋体" size="2">flush</font>
										</td>
										<td width="273">
												<font color="#000011" face="宋体" size="2">刷新流</font>
										</td>
								</tr>
								<tr>
										<td align="left" width="262">
												<font color="#ee0000" face="宋体" size="2">resetiosflags(long)</font>
										</td>
										<td width="273">
												<font color="#000011" face="宋体" size="2">请除特定的格式标志位</font>
										</td>
								</tr>
								<tr>
										<td align="left" width="262">
												<font color="#ee0000" face="宋体" size="2">setiosflags(long) </font>
										</td>
										<td width="273">
												<font color="#000011" face="宋体" size="2">设置特定的格式标志位</font>
										</td>
								</tr>
								<tr>
										<td align="left" width="262">
												<font color="#ee0000" face="宋体" size="2">setfill(char)</font>
										</td>
										<td width="273">
												<font color="#000011" face="宋体" size="2">设置填充字符</font>
										</td>
								</tr>
								<tr>
										<td align="left" width="262">
												<font color="#ee0000" face="宋体" size="2">setprecision(int)</font>
										</td>
										<td width="273">
												<font color="#000011" face="宋体" size="2">设置输出浮点数的精确度</font>
										</td>
								</tr>
								<tr>
										<td align="left" width="262">
												<font color="#ee0000" face="宋体" size="2">setw(int)</font>
										</td>
										<td width="273">
												<font color="#000011" face="宋体" size="2">设置域宽格式变量</font>
										</td>
								</tr>
						</tbody>
				</table>
		</div>
		<p language="Javascript1.2" id="fpAnimelasticRightFP11" style="left: 0px; visibility: visible; position: relative ! important; top: 0px;" endtop="0" endleft="0" inittop="0" initleft="802" startl="10" dynamicanimation="fpAnimelasticRightFP11">
				<b>
						<font face="宋体" size="2">其它流函数</font>
						<a name="75">
						</a>
				</b>
		</p>
		<p>
				<font color="#ff00ff">
						<font face="宋体" size="2">错误处理</font>
						<br />
				</font>
				<font size="2">
						<font face="宋体">    <font color="#000011">在对一个流对象进行I/O操作时，可能会产生错误。当错误发生时，错误的性质被记录在ios类的一个数据成员中。</font></font>
				</font>
				<font color="#ee0000">
						<br />
						<font face="宋体" size="2">ios类中定义的描述错误状态的常量:</font>
				</font>
		</p>
		<div align="left">
		</div>
		<p>
		</p>
		<table border="1" cellpadding="0" height="150" width="546">
				<tbody>
						<tr>
								<td align="left" height="18" width="150">
										<font size="2">
												<font face="宋体">
														<font color="#ee0000">goodbit</font>
														<font color="#000011"> </font>
												</font>
										</font>
								</td>
								<td height="18" width="285">
										<font size="2">
												<font face="宋体">
														<font color="#000011">没有错误，正常状态　 </font>
														<font color="#ee0000">eofbit </font>
														<font color="#000011">到达流的结尾  </font>
												</font>
										</font>
								</td>
						</tr>
						<tr>
								<td align="left" height="18" width="250">
										<font color="#ee0000" face="宋体" size="2">failbit</font>
								</td>
								<td height="18" width="285">
										<font color="#000011" face="宋体" size="2">I/O操作失败，清除状态字后，可以对流继续进行操作。</font>
								</td>
						</tr>
						<tr>
								<td align="left" height="18" width="250">
										<font color="#ee0000" face="宋体" size="2">badbit</font>
								</td>
								<td height="18" width="285">
										<font color="#000011" face="宋体" size="2">试图进行非法操作，清除状态字后，流可能还可以使用。</font>
								</td>
						</tr>
						<tr>
								<td align="left" height="18" width="250">
										<font color="#ee0000" face="宋体" size="2">hardfail</font>
								</td>
								<td height="18" width="285">
										<font color="#000011" face="宋体" size="2">致命错误，不可恢复的错误。</font>
								</td>
						</tr>
				</tbody>
		</table>
		<font color="#000011">
				<font face="宋体" size="2">
						<font color="#ff00ff" face="宋体" size="2">
								<br />ostream类的成员函数<br /></font>流的其它成员函数可以从流中读取字符或字符串，对流进行无格式化的输入 输出操作，以及直接控制对流的I/O操作。</font>
		</font>
		<div align="left">
		</div>
		<p>
		</p>
		<table border="1" cellpadding="0" width="545">
				<tbody>
						<tr>
								<td align="left" width="103">
										<font color="#000011" face="宋体" size="2">返回类型</font>
								</td>
								<td align="left" width="148">
										<font color="#000011" face="宋体" size="2">ios类的成员</font>
								</td>
								<td align="center" width="280">
										<font color="#000011" face="宋体" size="2">描　　　　　　述</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="103">
										<font color="#ee0000" face="宋体" size="2">ostream*</font>
								</td>
								<td align="left" width="148">
										<font color="#ee0000" face="宋体" size="2">tie(ostream*)</font>
								</td>
								<td width="280">
										<font size="2">
												<font face="宋体">
														<font color="#000011">   将当前流与指定的输出流连接起来。每当需要 读取当前流时，连接的流会自动刷新。C++流库已用cin.tie(cout)将输入流与输出流连接</font>
														<font color="#000011">起来。要取消与输出流的连接可采用is.tie(0)</font>
												</font>
										</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="103">
										<font color="#ee0000" face="宋体" size="2">ostream*</font>
								</td>
								<td align="left" width="148">
										<font color="#ee0000" face="宋体" size="2">tie( )</font>
								</td>
								<td width="280">
										<font color="#000011" face="宋体" size="2">返回指向连接流的指针</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p align="justify">
				<font size="2">
						<br />
				</font>
		</p>
		<div align="left">
				<font color="#000011">
				</font>
				<font color="#000011">
				</font>
				<font color="#000011">
				</font>
				<font color="#000011">
				</font>
				<font color="#000011">
				</font>
				<font color="#000011">
				</font>
				<font color="#000011">
				</font>
		</div>
		<p>
		</p>
		<table border="1" cellpadding="0" width="545">
				<tbody>
						<tr>
								<td align="left" width="104">
										<font color="#000011" face="宋体" size="2">返回类型</font>
								</td>
								<td align="left" width="169">
										<font color="#000011" face="宋体" size="2">ostream类的成员</font>
								</td>
								<td align="center" width="258">
										<font color="#000011" face="宋体" size="2">描　　　　　　述</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="104">
										<font color="#ee0000" face="宋体" size="2">ostream&amp;</font>
								</td>
								<td align="left" width="169">
										<font color="#ee0000" face="宋体" size="2">put(char ch)</font>
								</td>
								<td width="258">
										<font color="#000011" face="宋体" size="2">向流中输出一个字符ch，不进行任何转换</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="104">
										<font color="#ee0000" face="宋体" size="2">ostream&amp;</font>
								</td>
								<td align="left" width="169">
										<font color="#ee0000" face="宋体" size="2">write(char*,int)</font>
								</td>
								<td width="258">
										<font color="#000011" face="宋体" size="2">向流中输出指定长度的字符串，不进行转换</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="104">
										<font color="#ee0000" face="宋体" size="2">ostream&amp; </font>
								</td>
								<td align="left" width="169">
										<font color="#ee0000" face="宋体" size="2">flush( )</font>
								</td>
								<td width="258">
										<font color="#000011" face="宋体" size="2">刷新流，输出所有缓冲的但还未输出的数据</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="104">
										<font color="#ee0000" face="宋体" size="2">ostream&amp;</font>
								</td>
								<td align="left" width="169">
										<font color="#ee0000" face="宋体" size="2">seekp(streampos)</font>
								</td>
								<td width="258">
										<font color="#000011" face="宋体" size="2">移动流的当前指针到给定的绝对位置</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="104">
										<font color="#ee0000" face="宋体" size="2">ostream&amp;</font>
								</td>
								<td align="left" width="169">
										<font color="#ee0000" face="宋体" size="2">seekp(sereamoff,seek_dir)</font>
								</td>
								<td width="258">
										<font color="#000011" face="宋体" size="2">流的当前指针类似与文件的当前指针</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="104">
										<font color="#ee0000" face="宋体" size="2">streampos</font>
								</td>
								<td align="left" width="169">
										<font color="#ee0000" face="宋体" size="2">teelp( )</font>
								</td>
								<td width="258">
										<font color="#000011" face="宋体" size="2">返回流的当前指针的绝对位置</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p align="justify">
				<font color="#ff00ff" face="宋体" size="2">istream类的成员函数</font>
		</p>
		<table border="1" cellpadding="0" width="545">
				<tbody>
						<tr>
								<td align="left" width="87">
										<font color="#000011" face="宋体" size="2">返回类型</font>
								</td>
								<td align="left" width="245">
										<font color="#000011" face="宋体" size="2">istream类的成员</font>
								</td>
								<td align="center" width="199">
										<font color="#000011" face="宋体" size="2">描　　　　　　　　述</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="87">
										<font color="#ee0000" face="宋体" size="2">int</font>
								</td>
								<td align="left" width="245">
										<font color="#ee0000" face="宋体" size="2">get( )</font>
								</td>
								<td width="199">
										<font color="#000011" face="宋体" size="2">读取并返回一个字符</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="87">
										<font color="#ee0000" face="宋体" size="2">istream&amp;</font>
								</td>
								<td align="left" width="245">
										<font color="#ee0000" face="宋体" size="2">get(char&amp;c)</font>
								</td>
								<td width="199">
										<font color="#000011" face="宋体" size="2">读取字符并存入c中</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="87">
										<font color="#ee0000" face="宋体" size="2">istream&amp;</font>
								</td>
								<td align="left" width="245">
										<font color="#ee0000" face="宋体" size="2">get(char*ptr,int len,char delim='')</font>
								</td>
								<td width="199">
										<font color="#000011" face="宋体" size="2">读取指定的字符到缓冲区中，直到遇到指定的分界符为止，分界符不填入缓冲区。</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="87">
										<font color="#ee0000" face="宋体" size="2">istream&amp;</font>
								</td>
								<td align="left" width="245">
										<font size="2">
												<font face="宋体">
														<font color="#ee0000">getline(char*ptr,int </font>
														<font color="#ee0000">len,char delim='')</font>
												</font>
										</font>
								</td>
								<td width="199">
										<font size="2">
												<font face="宋体">
														<font color="#000011">与get(char*ptr,int len,chardelim =''） 类似，但将分界符填</font>
														<font color="#000011">入缓冲区。</font>
												</font>
										</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="87">
										<font color="#ee0000" face="宋体" size="2">istream&amp;</font>
								</td>
								<td align="left" width="245">
										<font color="#ee0000" face="宋体" size="2">putback( )</font>
								</td>
								<td width="199">
										<font color="#000011" face="宋体" size="2">将最近读取的字符放回流中</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="87">
										<font color="#ee0000" face="宋体" size="2">istream&amp;</font>
								</td>
								<td align="left" width="245">
										<font color="#ee0000" face="宋体" size="2">read(char*,int)<br /></font>
								</td>
								<td width="199">
										<font color="#000011" face="宋体" size="2">读取规定长度的字符串到缓冲区中<br />函数gcount()返回读取的字节数<br /></font>
								</td>
						</tr>
						<tr>
								<td align="left" width="87">
										<font color="#ee0000" face="宋体" size="2">int</font>
								</td>
								<td align="left" width="245">
										<font color="#ee0000" face="宋体" size="2">peek( ) </font>
								</td>
								<td width="199">
										<font size="2">
												<font face="宋体">
														<font color="#000011">返回流中下一个字符，但不移动文</font>
														<font color="#000011">件指针</font>
												</font>
										</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="87">
										<font color="#ee0000" face="宋体" size="2">istream&amp;</font>
								</td>
								<td align="left" width="245">
										<font color="#ee0000" face="宋体" size="2">seekg(streampos)</font>
								</td>
								<td width="199">
										<font color="#000011" face="宋体" size="2">移动当前指针到一绝对地址</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="87">
										<font color="#ee0000" face="宋体" size="2">istream&amp; </font>
								</td>
								<td align="left" width="245">
										<font color="#ee0000" face="宋体" size="2">seekg(streampos,seek_dir)</font>
								</td>
								<td width="199">
										<font color="#000011" face="宋体" size="2">移动当前指针到一相对地址</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="87">
										<font color="#ee0000" face="宋体" size="2">streampos</font>
								</td>
								<td align="left" width="245">
										<font color="#ee0000" face="宋体" size="2">tellg( )</font>
								</td>
								<td width="199">
										<font color="#000011" face="宋体" size="2">返回当前指针</font>
								</td>
						</tr>
						<tr>
								<td align="left" width="87">
										<font color="#ee0000" face="宋体" size="2">istream&amp;</font>
								</td>
								<td align="left" width="245">
										<font color="#ee0000" face="宋体" size="2">ignore(int n=1,delim=EOF)</font>
								</td>
								<td width="199">
										<font color="#000011" face="宋体" size="2">跳过流中几个字符，或直到遇到指定的分界符为止</font>
								</td>
						</tr>
				</tbody>
		</table>
		<br />getch()函数用于从键盘输入一个字符，不回显，包含头文件&lt;conio.h&gt;中<br /><img src ="http://www.cppblog.com/lmlf001/aggbug/5761.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-17 16:15 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/17/5761.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符串处理函数</title><link>http://www.cppblog.com/lmlf001/archive/2006/04/17/5756.html</link><dc:creator>芥之舟</dc:creator><author>芥之舟</author><pubDate>Mon, 17 Apr 2006 08:05:00 GMT</pubDate><guid>http://www.cppblog.com/lmlf001/archive/2006/04/17/5756.html</guid><wfw:comment>http://www.cppblog.com/lmlf001/comments/5756.html</wfw:comment><comments>http://www.cppblog.com/lmlf001/archive/2006/04/17/5756.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lmlf001/comments/commentRss/5756.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lmlf001/services/trackbacks/5756.html</trackback:ping><description><![CDATA[char *strcpy(char *s1, const char *s2)<br />将字符串s2复制到字符串数组s1中，返回s1的值<br /><br />char *strncpy(char *s1, const char *s2, size_t n)  <br />将字符串s2中最多n个字符复制到字符串数组s1中，返回s1的值<br />//当n &lt;strlen(s2)时，系统不自动在s1结尾添加null字符<br /><br />char *strcat(char *s1, const char *s2)<br />将字符串s2添加到字符串s1的后面。s2的第一个字符重定义s1的null终止符。返回s1的值<br /><br />char *strncat(char *s1, const char *s2, size_t n)<br />将字符串s2中最多n个字符添加到字符串s1的后面。s2的第一个字符重定义s1的null终止符。返回s1的值<br />//函数在s1结尾自动添加null字符<br /><br />int strcmp(const char *s1, const char *s2)<br />比较字符串s1和字符串s2。函数在s1等于、小于或大于s2时分别返回0、小于0或者大于0的值<br /><br />int strncmp(const char *s1, const char *s2, size_t n)<br />比较字符串s1中的n个字符和字符串s2。函数在s1等于、小于或大于s2时分别返回0、小于0或者大于0的值<br /><br />char * strtok(char *s1,const char *s2)<br />用
一系列strtok调用将s1字符串标记化(将字符串分成各个逻辑组件，如同一行文本中的每个单词)，用字符串s2所包含的字符分隔。首次调用时包含s1
为第一个参数，后面调用时继续标记化同一字符串，包含NULL为第一个参数。每次调用时返回当前标记指针。如果函数调用时不再有更多标记，则返回NULL<br /><br />size_t strlen(const char *s)<br />确定字符串长度,返回null终止符之前的字符数 <img src ="http://www.cppblog.com/lmlf001/aggbug/5756.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lmlf001/" target="_blank">芥之舟</a> 2006-04-17 16:05 <a href="http://www.cppblog.com/lmlf001/archive/2006/04/17/5756.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>