﻿<?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++</title><link>http://www.cppblog.com/maosher/category/10169.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 18 Feb 2011 12:53:07 GMT</lastBuildDate><pubDate>Fri, 18 Feb 2011 12:53:07 GMT</pubDate><ttl>60</ttl><item><title>新手的时候碰到的预处理命令</title><link>http://www.cppblog.com/maosher/archive/2011/02/17/140191.html</link><dc:creator>Brandon</dc:creator><author>Brandon</author><pubDate>Wed, 16 Feb 2011 16:04:00 GMT</pubDate><guid>http://www.cppblog.com/maosher/archive/2011/02/17/140191.html</guid><wfw:comment>http://www.cppblog.com/maosher/comments/140191.html</wfw:comment><comments>http://www.cppblog.com/maosher/archive/2011/02/17/140191.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/maosher/comments/commentRss/140191.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/maosher/services/trackbacks/140191.html</trackback:ping><description><![CDATA[今天一个新同学来问一个典型的预处理的问题，我当年也碰到这样的问题，贴出来，让更多的人能直接搜到<br><br>
<h1>预处理命令</h1>
<hr>
<h2><a name="">#,## </a></h2>
<p># 和 ## 操作符是和<a href="mk:@MSITStore:E:\doc\C++%20语言参考.chm::/cppreference.com/preproc_details.html#define"><u><font color=#810081>#define</font></u></a>宏使用的. 使用# 使在#后的首个参数返回为一个带引号的字符串. 例如, 命令 </p>
<pre>    #define to_string( s ) # s
</pre>
<p>将会使编译器把以下命令 </p>
<pre>    cout &lt;&lt; to_string( Hello World! ) &lt;&lt; endl;
</pre>
<p>理解为 </p>
<pre>    cout &lt;&lt; "Hello World!" &lt;&lt; endl;
</pre>
<p>使用##连结##前后的内容. 例如, 命令 </p>
<pre>    #define concatenate( x, y ) x ## y
...
int xy = 10;
...
</pre>
<p>将会使编译器把 </p>
<pre>    cout &lt;&lt; concatenate( x, y ) &lt;&lt; endl;
</pre>
<p>解释为 </p>
<pre>    cout &lt;&lt; xy &lt;&lt; endl;
</pre>
<p>理所当然,将会在标准输出处显示'10'.</p>
<br><br>
<h2><a name=line>#line</a> </h2>
<em>语法:</em>
<table bgColor=#ccccff>
    <tbody>
        <tr>
            <td>
            <pre>  #line line_number "filename"
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>#line命令是用于更改__LINE__ 和 __FILE__变量的值. 文件名是可选的. __LINE__ 和 __FILE__ 变量描述被读取的当前文件和行. 命令 </p>
<pre>    #line 10 "main.cpp"
</pre>
<p>更改行号为10,当前文件改为"main.cpp". <br><br><br></p>
<h2><a name=predefined>预定义变量</a> </h2>
<p><em>语法:</em>
<table bgColor=#ccccff>
    <tbody>
        <tr>
            <td>
            <pre>  __LINE__
            __FILE__
            __DATE__
            __TIME__
            _cplusplus
            __STDC__
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>下列参数在不同的编译器可能会有所不同, 但是一般是可用的:
<ul>
    <li>__LINE__ 和 __FILE__ 变量表示正在处理的当前行和当前文件.
    <li>__DATE__ 变量表示当前日期,格式为<em>month/day/year</em>(月/日/年).
    <li>__TIME__ 变量描述当前的时间,格式为<em>hour:minute:second</em>(时:分:秒).
    <li>_cplusplus 变量只在编译一个C++程序时定义.
    <li>__STDC__ 变量在编译一个C程序时定义,编译C++时也有可能定义. </li>
</ul>
<br>
<img src ="http://www.cppblog.com/maosher/aggbug/140191.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/maosher/" target="_blank">Brandon</a> 2011-02-17 00:04 <a href="http://www.cppblog.com/maosher/archive/2011/02/17/140191.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>好吧，我被征服了—— 关于 c++ unsigned char </title><link>http://www.cppblog.com/maosher/archive/2011/02/13/139977.html</link><dc:creator>Brandon</dc:creator><author>Brandon</author><pubDate>Sun, 13 Feb 2011 08:12:00 GMT</pubDate><guid>http://www.cppblog.com/maosher/archive/2011/02/13/139977.html</guid><wfw:comment>http://www.cppblog.com/maosher/comments/139977.html</wfw:comment><comments>http://www.cppblog.com/maosher/archive/2011/02/13/139977.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/maosher/comments/commentRss/139977.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/maosher/services/trackbacks/139977.html</trackback:ping><description><![CDATA[<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008080;">1</span>&nbsp;<span style="color: #000000;">unsigned&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;i;<br></span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">i</span><span style="color: #000000;">=-</span><span style="color: #000000;">20</span><span style="color: #000000;">;<br></span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;"></span></div>
上面一段很简单的代码，如果输出会是什么 呢？<br>今天群里的新学c++同学问我，unsighed char 和char 有啥区别，上面的输出会有什么 不同<br>在这里，我先鄙视一下自己，我直观的理解为通常的 首位符号位，然后丢下的就是输入无符号的。好吧，估计各位看官说我太菜，但确实是输出的结果和我想的不大一样，如果各位没明白我说的是什么问题，可以试一下。然后回来看下面的内容。<br><br><br><br><br><br><br><br><br><br><br><br><br>。<br>
<p class="docText">In an <tt>unsigned</tt> type, all the bits represent the value.
If a type is defined for a particular machine to use 8 bits, then the
<tt>unsigned</tt> version of this type could hold the values 0 through 255.</p>
<p class="docText">无符号型中，所有的位都表示数值。如果在某种机器中，定义一种类型使用 8 位表示，那么这种类型的
<tt>unsigned</tt> 型可以取值 0 到 255。</p>
<p class="docText">The C++ standard does not define how <tt>signed</tt> types are
represented at the bit level. Instead, each compiler is free to decide how it
will represent <tt>signed</tt> types. These representations can affect the range
of values that a <tt>signed</tt> type can hold. We are guaranteed that an 8-bit
<tt>signed</tt> type will hold at least the values from 127 through 127; many
implementations allow values from 128 through 127.</p>
<p class="docText">C++ 标准并未定义 <tt>signed</tt> 类型如何用位来表示，而是由每个编译器自由决定如何表示
<tt>signed</tt> 类型。这些表示方式会影响 <tt>signed</tt> 类型的取值范围。8 位 <tt>signed</tt>
类型的取值肯定至少是从 -127 到 127，但也有许多实现允许取值从 -128 到 127。</p>
<p class="docText">Under the most common strategy for representing <tt>signed</tt>
integral types, we can view one of the bits as a sign bit. Whenever the sign bit
is 1, the value is negative; when it is 0, the value is either 0 or a positive
number. An 8-bit integral <tt>signed</tt> type represented using a sign-bit can
hold values from 128 through 127.</p>
<p class="docText">表示 <tt>signed</tt> 整型类型最常见的策略是用其中一个位作为符号位。符号位为 1，值就为负数；符号位为
0，值就为 0 或正数。一个 <tt>signed</tt> 整型取值是从 -128 到 127。</p>
<a name="ch02lev3sec3"></a>
<h5 class="docSection3Title">Assignment to Integral Types</h5>
<h5 class="docSection3Title">整型的赋值</h5>
<a name="idd1e7331"></a><a name="idd1e7340"></a><a name="idd1e7349"></a><a name="idd1e7359"></a><a name="idd1e7369"></a><a name="idd1e7373"></a><a name="idd1e7380"></a><a name="idd1e7384"></a><a name="idd1e7387"></a><a name="idd1e7390"></a><a name="idd1e7394"></a><a name="idd1e7401"></a><a name="idd1e7413"></a>
<p class="docText">The type of an object determines the values that the object can
hold. This fact raises the question of what happens when one tries to assign a
value outside the allowable range to an object of a given type. The answer
depends on whether the type is <tt>signed</tt> or <tt>unsigned</tt>.</p>
<p class="docText">对象的类型决定对象的取值。这会引起一个疑问：当我们试着把一个超出其取值范围的值赋给一个指定类型的对象时，结果会怎样呢？答案取决于这种类型是
<tt>signed</tt> 还是 <tt>unsigned</tt> 的。</p>
<p class="docText">For <tt>unsigned</tt> types, the compiler <span class="docEmphasis">must</span> adjust the out-of-range value so that it will fit.
The compiler does so by taking the remainder of the value modulo the number of
distinct values the <tt>unsigned</tt> target type can hold. An object that is an
8-bit <tt>unsigned char</tt>, for example, can hold values from 0 through 255
inclusive. If we assign a value outside this range, the compiler actually
assigns the remainder of the value modulo 256. For example, we might attempt to
assign the value 336 to an 8-bit <tt>signed char</tt>. If we try to store 336 in
our 8-bit <tt>unsigned char</tt>, the actual value assigned will be 80, because
80 is equal to 336 modulo 256.</p>
<p class="docText">对于 <tt>unsigned</tt> 类型来说，编译器必须调整越界值使其满足要求。编译器会将该值对
<tt>unsigned</tt> 类型的可能取值数目求模，然后取所得值。比如 8 位的 <tt>unsigned char</tt>，其取值范围从 0 到
255（包括 255）。如果赋给超出这个范围的值，那么编译器将会取该值对 256 求模后的值。例如，如果试图将 336 存储到 8 位的
<tt>unsigned char</tt> 中，则实际赋值为 80，因为 80 是 336 对 256 求模后的值。</p>
<p class="docText">For the <tt>unsigned</tt> types, a negative value is always out
of range. An object of <tt>unsigned</tt> type may never hold a negative value.
Some languages make it illegal to assign a negative value to an
<tt>unsigned</tt> type, but C++ does not.</p>
<p class="docText">对于 <tt>unsigned</tt> 类型来说，负数总是超出其取值范围。<tt>unsigned</tt>
类型的对象可能永远不会保存负数。有些语言中将负数赋给 <tt>unsigned</tt> 类型是非法的，但在 C++ 中这是合法的。</p>
<a name="ch02note02"></a>
<div class="docNote">
<table style="width: 861px; height: 116px;" border="0" cellpadding="1" cellspacing="0">
    <tbody>
        <tr>
            <td valign="top" width="60"><br></td>
            <td valign="top">
            <p class="docText">In C++ it is perfectly legal to assign a negative number to an
            object with <tt>unsigned</tt> type. The result is the negative value modulo the
            size of the type. So, if we assign 1 to an 8-bit <tt>unsigned char</tt>, the
            resulting value will be 255, which is 1 modulo 256.</p>
            <p class="docText">C++ 中，把负值赋给 <tt>unsigned</tt>
            对象是完全合法的，其结果是该负数对该类型的取值个数求模后的值。所以，如果把 -1 赋给8位的 <tt>unsigned char</tt>，那么结果是
            255，因为 255 是 -1 对 256 求模后的值。</p>
            </td>
        </tr>
    </tbody>
</table>
<br></div>
<br>
<p class="docText">When assigning an out-of-range value to a <tt>signed</tt> type,
it is up to the compiler to decide what value to assign. In practice, many
compilers treat <tt>signed</tt> types similarly to how they are required to
treat <tt>unsigned</tt> types. That is, they do the assignment as the remainder
modulo the size of the type. However, we are not guaranteed that the compiler
will do so for the <tt>signed</tt> types.</p>
<p class="docText">当将超过取值范围的值赋给 <tt>signed</tt> 类型时，由编译器决定实际赋的值。在实际操作中，很多的编译器处理
<tt>signed</tt> 类型的方式和 <tt>unsigned</tt>
类型类似。也就是说，赋值时是取该值对该类型取值数目求模后的值。然而我们不能保证编译器都会这样处理 <tt>signed</tt> 类型。</p>
<p class="docText"><br></p>
<p class="docText"><br></p>
<p class="docText">以上摘自 c++ primer,惭愧，还是再细细的从头品一次这书吧。<br></p>
<p class="docText"></p>
<p class="docText"><br></p>
<br><br><br><br><br><br><br><img src ="http://www.cppblog.com/maosher/aggbug/139977.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/maosher/" target="_blank">Brandon</a> 2011-02-13 16:12 <a href="http://www.cppblog.com/maosher/archive/2011/02/13/139977.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c语言中可变参数函数的设计</title><link>http://www.cppblog.com/maosher/archive/2010/06/17/118126.html</link><dc:creator>Brandon</dc:creator><author>Brandon</author><pubDate>Thu, 17 Jun 2010 15:52:00 GMT</pubDate><guid>http://www.cppblog.com/maosher/archive/2010/06/17/118126.html</guid><wfw:comment>http://www.cppblog.com/maosher/comments/118126.html</wfw:comment><comments>http://www.cppblog.com/maosher/archive/2010/06/17/118126.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/maosher/comments/commentRss/118126.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/maosher/services/trackbacks/118126.html</trackback:ping><description><![CDATA[1，首先，怎么得到参数的值。对于一般的函数，我们可以通过参数对应在参数列表里的标识符来得到。但是参数可变函数那些可变的参数是没有参数标识符的，它只有&#8220;&#8230;&#8221;，所以通过标识符来得到是不可能的，我们只有另辟途径。<br><br>我们知道函数调用时都会分配栈空间，而函数调用机制中的栈结构如下图所示：<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; ......&nbsp;&nbsp;&nbsp;&nbsp; |<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ------------------<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 参数2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ------------------<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 参数1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ------------------<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; 返回地址&nbsp;&nbsp;&nbsp; |<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ------------------<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |调用函数运行状态|<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ------------------<br><br>可见，参数是连续存储在栈里面的，那么也就是说，我们只要得到可变参数的前一个参数的地址，就可以通过指针访问到那些可变参数。但是怎么样得到可变参数的前一个参数的地址呢？不知道你注意到没有，参数可变函数在可变参数之前必有一个参数是固定的，并使用标识符，而且通常被声明为char*类型，printf函数也不例外。这样的话，我们就可以通过这个参数对应的标识符来得到地址，从而访问其他参数变得可能。我们可以写一个测试程序来试一下：<br><br>#include &lt;stdio.h&gt;<br><br><br><br>void va_test(char* fmt,...);//参数可变的函数声明<br><br><br><br>void main()<br><br>{<br><br>&nbsp;&nbsp;&nbsp; int a=1,c=55;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char b='b';<br><br>&nbsp;&nbsp;&nbsp; va_test("",a,b,c);//用四个参数做测试<br><br>}<br><br><br><br>void va_test(char* fmt,...) //参数可变的函数定义，注意第一个参数为char* fmt<br><br>{<br><br>&nbsp;&nbsp; char *p=NULL;<br><br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p=(char *)&amp;fmt;//注意不是指向fmt，而是指向&amp;fmt，并且强制转化为char *,以便一个一个字节访问<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i = 0;i&lt;16;i++)//16是通过计算的值（参数个数*4个字节），只是为了测试，暂且将就一下<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("%.4d ",*p);//输出p指针指向地址的值<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p++;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>}<br><br><br><br>编译运行的结果为<br><br>0056 0000 0066 0000 | 0001 0000 0000 0000 | 0098 0000 0000 0000 | 0055 0000 0000 0000<br><br><br><br>由运行结果可见，通过这样方式可以逐一获得可变参数的值。<br><br>至于为什么通常被声明为char*类型，我们慢慢看来。<br><br>2，怎样确定参数类型和数量<br><br>通过上述的方式，我们首先解决了取得可变参数值的问题，但是对于一个参数，值很重要，其类型同样举足轻重，而对于一个函数来讲参数个数也非常重要，否则就会产生了一系列的麻烦来。通过访问存储参数的栈空间，我们并不能得到关于类型的任何信息和参数个数的任何信息。我想你应该想到了——使用char *参数。Printf函数就是这样实现的，它把后面的可变参数类型都放到了char *指向的字符数组里，并通过%来标识以便与其它的字符相区别，从而确定了参数类型也确定了参数个数。其实，用何种方式来到达这样的效果取决于函数的实现。比如说，定义一个函数，预知它的可变参数类型都是int，那么固定参数完全可以用int类型来替换char*类型，因为只要得到参数个数就可以了。<br><br>3，言归正传<br><br>&nbsp;&nbsp; 我想到了这里，大概的轮廓已经呈现出来了。本来想就此作罢的（我的惰性使然），但是一想到如果不具实用性便可能是一堆废物，枉费我打了这么些字，决定还是继续下去。<br><br>&nbsp;&nbsp; 我是比较抵制用那些不明所以的宏定义的，所以在上面的阐述里一点都没有涉及定义在&lt;stdarg.h&gt;的va(variable-argument)宏。事实上，当时让我产生极大疑惑和好奇的正是这几个宏定义。但是现在我们不得不要去和这些宏定义打打交道，毕竟我们在讨生计的时候还得用上他们，这也是我曰之为&#8220;言归正传&#8221;的理由。<br><br>&nbsp;&nbsp; 好了，我们来看一下那些宏定义。<br><br>&nbsp;&nbsp; 打开&lt;stdarg.h&gt;文件，找一下va_*的宏定义，发现不单单只有一组，但是在各组定义前都会有宏编译。宏编译指示的是不同硬件平台和编译器下用怎样的va宏定义。比较一下，不同之处主要在偏移量的计算上。我们还是拿个典型又熟悉的——X86的相关宏定义：<br><br>1)typedef char * va_list;<br><br>2)#define _INTSIZEOF(n)&nbsp;&nbsp; ( (sizeof(n) + sizeof(int) - 1) &amp; ~(sizeof(int) - 1) )<br><br><br><br>3)#define va_start(ap,v) ( ap = (va_list)&amp;v + _INTSIZEOF(v) )<br><br>4)#define va_arg(ap,t)&nbsp;&nbsp;&nbsp; ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )<br><br>5)#define va_end(ap)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( ap = (va_list)0 )<br><br><br><br>我们逐一看来：<br><br>第一个我想不必说了，类型定义罢了。第二个是颇有些来头的，我们也不得不搞懂它，因为后面的两个关键的宏定义都用到了。不知道你够不够细心，有没有发现在上面的测试程序中，第二个可变参数明明是char类型，可是在输出结果中占了4个byte。难道所有的参数都会占4个byte的空间？那如果是double类型的参数，且不是会丢失数据！如果你不嫌麻烦的话，再去做个测试吧，在上面的测试程序中用一个double类型（长度为8byte）和一个long double类型（长度为10byte）做可变参数。发现什么？double类型占了8byte,而long double占了12byte。好像都是4的整数倍哦。不得不引出另一个概念了&#8220;对齐（alignment）&#8221;,所谓对齐，对Intel80x86 机器来说就是要求每个变量的地址都是sizeof(int)的倍数。原来我们搞错了，char类型的参数只占了1byte，但是它后面的参数因为对齐的关系只能跳过3byte存储，而那3byte也就浪费掉了。那为什么要对齐？因为在对齐方式下，CPU 的运行效率要快得多（举个例子吧，要说明的是下面的例子是我从网上摘录下来的，不记得出处了。<br><br>示例：如下图，当一个long 型数（如图中long1）在内存中的位置正好与内存的字边界对齐时，CPU 存取这个数只需访问一次内存，而当一个long 型数（如图中的long2）在内存中的位置跨越了字边界时，CPU 存取这个数就需要多次访问内存，如i960cx 访问这样的数需读内存三次（一个BYTE、一个SHORT、一个BYTE，由CPU 的微代码执行，对软件透明），所以对齐方式下CPU 的运行效率明显快多了。<br><br>1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 32&nbsp;&nbsp; <br><br>------- ------- ------- ---------<br><br>| long1 | long1 | long1 | long1 |<br><br>------- ------- ------- ---------<br><br>|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | long2 |<br><br>------- ------- ------- ---------<br><br>| long2 | long2 | long2 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br><br>------- ------- ------- ---------<br><br>| ....)。好像扯得有点远来，但是有助于对_INTSIZEOF(n)的理解。位操作对于我来说是玄的东东。单个位运算还应付得来，而这样一个表达式摆在面前就晕了。怎么办？菜鸟自有菜的办法。(待续)<br><br><br>Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=14721<br><br>---------------------------------------------------------------------------------------------------------------------<br><br>C语言中的可变参数函数&nbsp;&nbsp;&nbsp; CSDN Blog推出文章指数概念，文章指数是对Blog文章综合评分后推算出的，综合评分项分别是该文章的点击量，回复次数，被网摘收录数量，文章长度和文章类型；满分100，每月更新一次。<br><br>第一篇<br><br>C语言编程中有时会遇到一些参数个数可变的函数,例如printf()函数,其函数原型为：<br><br>int printf( const char* format, ...);<br><br>它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的（用三个点&#8220;&#8230;&#8221;做参数占位符）,实际调用时可以有以下的形式：<br><br>printf("%d",i);<br>printf("%s",s);<br>printf("the number is %d ,string is:%s", i, s);&nbsp;&nbsp; <br><br>一个简单的可变参数的C函数<br><br>&nbsp;&nbsp;&nbsp;&nbsp; 先看例子程序。该函数至少有一个整数参数,其后占位符&#8230;，表示后面参数的个数不定。在这个例子里，所有的输入参数必须都是整数，函数的功能只是打印所有参数的值。函数代码如下：<br><br>//示例代码1：可变参数函数的使用<br>#include "stdio.h"<br>#include "stdarg.h"<br>void simple_va_fun(int start, ...)<br>{<br>&nbsp;&nbsp;&nbsp; va_list arg_ptr;<br>&nbsp;&nbsp;&nbsp; int nArgValue =start;<br>&nbsp;&nbsp;&nbsp; int nArgCout="0"; //可变参数的数目<br>&nbsp;&nbsp;&nbsp; va_start(arg_ptr,start); //以固定参数的地址为起点确定变参的内存起始地址。<br>&nbsp;&nbsp;&nbsp; do<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++nArgCout;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("the %d th arg: %d",nArgCout,nArgValue); //输出各参数的值<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nArgValue = va_arg(arg_ptr,int); //得到下一个可变参数的值<br>&nbsp;&nbsp;&nbsp; } while(nArgValue != -1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; return;<br>}<br>int main(int argc, char* argv[])<br>{<br>&nbsp;&nbsp;&nbsp; simple_va_fun(100,-1);<br>&nbsp;&nbsp;&nbsp; simple_va_fun(100,200,-1);<br>&nbsp;&nbsp;&nbsp; return 0;<br>}<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><br>⑵函数里首先定义一个va_list型的变量,这里是arg_ptr,这个变量是存储参数地址的指针.因为得到参数的地址之后，再结合参数的类型，才能得到参数的值。<br><br>⑶然后用va_start宏初始化⑵中定义的变量arg_ptr,这个宏的第二个参数是可变参数列表的前一个参数,即最后一个固定参数。<br><br>⑷然后依次用va_arg宏使arg_ptr返回可变参数的地址,得到这个地址之后，结合参数的类型，就可以得到参数的值。<br><br>⑸设定结束条件，这里的条件就是判断参数值是否为-1。注意被调的函数在调用时是不知道可变参数的正确数目的，程序员必须自己在代码中指明结束条件。至于为什么它不会知道参数的数目，在看完这几个宏的内部实现机制后，自然就会明白。<br><br>第二篇<br><br>C语言之可变参数问题<br><br><br><br>C语言中有一种长度不确定的参数，形如："&#8230;"，它主要用在参数个数不确定的函数中，我们最容易想到的例子是printf函数。<br><br>　　原型：<br><br>　　int printf( const char *format [, argument]... );<br><br>　　使用例：<br><br>　　printf("Enjoy yourself everyday!\n");<br><br>　　printf("The value is %d!\n", value);<br><br>　　这种可变参数可以说是C语言一个比较难理解的部分，这里会由几个问题引发一些对它的分析。<br><br>　　注意：在C++中有函数重载（overload）可以用来区别不同函数参数的调用，但它还是不能表示任意数量的函数参数。<br><br>　　问题：printf的实现<br><br>　　请问，如何自己实现printf函数，如何处理其中的可变参数问题？ 答案与分析：<br><br>　　在标准C语言中定义了一个头文件专门用来对付可变参数列表，它包含了一组宏，和一个va_list的typedef声明。一个典型实现如下：<br><br>　　typedef char* va_list;<br><br>　　#define va_start(list) list = (char*)&amp;va_alist<br><br>　　#define va_end(list)<br><br>　　#define va_arg(list, mode)\<br><br>　　((mode*) (list += sizeof(mode)))[-1]<br><br>　　自己实现printf：<br><br>　　#include<br><br>　　int printf(char* format, &#8230;)<br><br>　　{<br><br>　　va_list ap;<br><br>　　va_start(ap, format);<br><br>　　int n = vprintf(format, ap);<br><br>　　va_end(ap);<br><br>　　return n;<br><br>　　}<br><br>　　问题：运行时才确定的参数<br><br>　　有没有办法写一个函数，这个函数参数的具体形式可以在运行时才确定？<br><br>　　答案与分析：<br><br>　　目前没有"正规"的解决办法，不过独门偏方倒是有一个，因为有一个函数已经给我们做出了这方面的榜样，那就是main()，它的原型是:<br><br>　　int main(int argc,char *argv[]);<br>函数的参数是argc和argv。<br><br>　　深入想一下，"只能在运行时确定参数形式"，也就是说你没办法从声明中看到所接受的参数，也即是参数根本就没有固定的形式。常用的办法是你可以通过定义一个void *类型的参数，用它来指向实际的参数区，然后在函数中根据根据需要任意解释它们的含义。这就是main函数中argv的含义，而argc，则用来表明实际的参数个数，这为我们使用提供了进一步的方便，当然，这个参数不是必需的。<br><br>　　虽然参数没有固定形式，但我们必然要在函数中解析参数的意义，因此，理所当然会有一个要求，就是调用者和被调者之间要对参数区内容的格式，大小，有效性等所有方面达成一致，否则南辕北辙各说各话就惨了。<br><br>　　问题：可变长参数的传递<br><br>　　有时候，需要编写一个函数，将它的可变长参数直接传递给另外的函数，请问，这个要求能否实现？<br><br>　　答案与分析：<br><br>　　目前，你尚无办法直接做到这一点，但是我们可以迂回前进，首先，我们定义被调用函数的参数为va_list类型，同时在调用函数中将可变长参数列表转换为va_list，这样就可以进行变长参数的传递了。看如下所示：<br><br>　　void subfunc (char *fmt, va_list argp)<br><br>　　{<br><br>　　...<br><br>　　arg = va_arg (fmt, argp); /* 从argp中逐一取出所要的参数 */<br><br>　　...<br><br>　　}<br><br>　　void mainfunc (char *fmt, ...)<br><br>　　{<br><br>　　va_list argp;<br><br>　　va_start (argp, fmt); /* 将可变长参数转换为va_list */<br><br>　　subfunc (fmt, argp); /* 将va_list传递给子函数 */<br><br>　　va_end (argp);<br><br>　　...<br><br>　　}<br><br>　　问题：可变长参数中类型为函数指针<br><br>　　我想使用va_arg来提取出可变长参数中类型为函数指针的参数，结果却总是不正确，为什么？<br><br>　　答案与分析：<br><br>　　这个与va_arg的实现有关。一个简单的、演示版的va_arg实现如下：<br><br>　　#define va_arg(argp, type) \<br><br>　　(*(type *)(((argp) += sizeof(type)) - sizeof(type)))<br><br>　　其中，argp的类型是char *。<br><br>　　如果你想用va_arg从可变参数列表中提取出函数指针类型的参数，例如<br><br>　　int (*)()，则va_arg(argp, int (*)())被扩展为：<br><br>　　(*(int (*)() *)(((argp) += sizeof (int (*)())) -sizeof (int (*)())))<br><br>　　显然，（int (*)() *）是无意义的。<br><br>　　解决这个问题的办法是将函数指针用typedef定义成一个独立的数据类型，例如：<br><br>　　typedef int (*funcptr)()；<br><br>　　这时候再调用va_arg(argp, funcptr)将被扩展为：<br><br>　　(* (funcptr *)(((argp) += sizeof (funcptr)) - sizeof (funcptr)))<br><br>　　这样就可以通过编译检查了。<br><br>　　问题：可变长参数的获取<br><br>　　有这样一个具有可变长参数的函数，其中有下列代码用来获取类型为float的实参：<br><br>　　va_arg (argp, float);<br><br>　　这样做可以吗？<br><br>　　答案与分析：<br><br>　　不可以。在可变长参数中，应用的是"加宽"原则。也就是float类型被扩展成double；char, short被扩展成int。因此，如果你要去可变长参数列表中原来为float类型的参数，需要用va_arg(argp, double)。对char和short类型的则用va_arg(argp, int)。<br><br>　　问题：定义可变长参数的一个限制<br><br>　　为什么我的编译器不允许我定义如下的函数，也就是可变长参数，但是没有任何的固定参数？<br><br>　　int f (...)<br><br>　　{<br><br>　　...<br><br>　　}<br><br>　　答案与分析：<br><br>　　不可以。这是ANSI C 所要求的，你至少得定义一个固定参数。<br><br>　　这个参数将被传递给va_start()，然后用va_arg()和va_end()来确定所有实际调用时可变长参数的类型和值。---------------------------------------------------------------------------------------------------------------------<br>如何判别可变参数函数的参数类型？<br><br>函数形式如下：<br>void&nbsp;&nbsp; fun(char*&nbsp;&nbsp; str,...)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......<br>}<br><br>若传的参数个数大于1，如何判别第2个以后传参的参数类型？？？<br>最好有源码说明！ <br><br><br>没办法判断的<br><br><br>如楼上所说,例如printf( "%d%c%s ",&nbsp;&nbsp; ....)是通过格式串中的%d,&nbsp;&nbsp; %c,&nbsp;&nbsp; %s来确定后面参数的类型,其实你也可以参考这种方法来判断不定参数的类型.<br><br><br>无法判断。可变参数实现主要通过三个宏实现：va_start,&nbsp;&nbsp; va_arg,&nbsp;&nbsp; va_end。<br><br><br>六、 扩展与思考<br><br>个数可变参数在声明时只需"..."即可；但是，我们在接受这些参数时不能"..."。va函数实现的关键就是如何得到参数列表中可选参数，包括参数的值和类型。以上的所有实现都是基于来自stdarg.h的va_xxx的宏定义。 &lt;思考&gt;能不能不借助于va_xxx，自己实现VA呢？，我想到的方法是汇编。在C中，我们当然就用C的嵌入汇编来实现，这应该是可以做得到的。至于能做到什么程度，稳定性和效率怎么样，主要要看你对内存和指针的控制了。<br><br>参考资料<br><br>1.IEEE和OpenGroup联合开发的Single Unix specification Ver3；BR&gt;<br>2.Linux man手册；<br><br>3.x86汇编，还有一些安全编码方面的资料。<br><br>---------------------------------------------------------------------------------------------------------------------<br>[转帖]对C/C++可变参数表的深层探索<br><br>C/C++语言有一个不同于其它语言的特性，即其支持可变参数，典型的函数如printf、scanf等可以接受数量不定的参数。如：<br>　　printf ( "I love you" );<br>　　printf ( "%d", a );<br>　　printf ( "%d,%d", a, b );<br>　　第一、二、三个printf分别接受1、2、3个参数，让我们看看printf函数的原型：<br>　　int printf ( const char *format, ... );<br>　　从函数原型可以看出，其除了接收一个固定的参数format以外，后面的参数用"&#8230;"表示。在C/C++语言中，"&#8230;"表示可以接受不定数量的参数，理论上来讲，可以是0或0以上的n个参数。<br>　　本文将对C/C++可变参数表的使用方法及C/C++支持可变参数表的深层机理进行探索。<br><br>　　一. 可变参数表的用法<br>　　1、相关宏<br>　　标准C/C++包含头文件stdarg.h，该头文件中定义了如下三个宏：<br>void va_start ( va_list arg_ptr, prev_param ); /* ANSI version */<br>type va_arg ( va_list arg_ptr, type );<br>void va_end ( va_list arg_ptr ); <br>　　在这些宏中，va就是variable argument(可变参数)的意思；arg_ptr是指向可变参数表的指针；prev_param则指可变参数表的前一个固定参数；type为可变参数的类型。va_list也是一个宏，其定义为typedef char * va_list，实质上是一 char型指针。char型指针的特点是++、--操作对其作用的结果是增1和减1（因为sizeof(char)为1），与之不同的是int等其它类型指针的++、--操作对其作用的结果是增sizeof(type)或减sizeof(type)，而且sizeof (type)大于1。<br>　　通过va_start宏我们可以取得可变参数表的首指针，这个宏的定义为：<br>#define va_start ( ap, v ) ( ap = (va_list)&amp;v + _INTSIZEOF(v) )<br>　　显而易见，其含义为将最后那个固定参数的地址加上可变参数对其的偏移后赋值给ap，这样ap就是可变参数表的首地址。其中的_INTSIZEOF宏定义为：<br>#define _INTSIZEOF(n) ((sizeof ( n ) + sizeof ( int ) - 1 ) &amp; ~( sizeof( int ) - 1 ) )<br>　　va_arg宏的意思则指取出当前arg_ptr所指的可变参数并将ap指针指向下一可变参数，其原型为：<br>#define va_arg(list, mode) ((mode *)(list =(char *) ((((int)list + (__builtin_alignof(mode)&lt;=4?3:7)) &amp;(__builtin_alignof(mode)&lt;=4?-4:-8))+sizeof(mode))))[-1]<br>　　对这个宏的具体含义我们将在后面深入讨论。<br>　　而va_end宏被用来结束可变参数的获取，其定义为：<br>#define va_end ( list )<br>　　可以看出，va_end ( list )实际上被定义为空，没有任何真实对应的代码，用于代码对称，与va_start对应；另外，它还可能发挥代码的"自注释"作用。所谓代码的"自注释"，指的是代码能自己注释自己。<br>　　下面我们以具体的例子来说明以上三个宏的使用方法。<br>　　2、一个简单的例子<br>　　#include &lt;stdarg.h&gt;<br>　　/*　函数名：max<br>　　*　功能：返回n个整数中的最大值<br>　　* 参数：num：整数的个数 ...：num个输入的整数<br>　　* 返回值：求得的最大整数<br>　　*/<br>　　int max ( int num, ... )<br>　　{<br>　　　int m = -0x7FFFFFFF; /* 32系统中最小的整数 */<br>　　　va_list ap;<br>　　　va_start ( ap, num );<br>　　　for ( int i= 0; i&lt; num; i++ )<br>　　　{<br>　　　　int t = va_arg (ap, int);<br>　　　　if ( t &gt; m )<br>　　　　{<br>　　　　　m = t;<br>　　　　}<br>　　　}<br>　　　va_end (ap);<br>　　　return m;<br>　　}<br>　　/* 主函数调用max */<br>　　int main ( int argc, char* argv[] )<br>　　{<br>　　　int n = max ( 5, 5, 6 ,3 ,8 ,5); /* 求5个整数中的最大值 */<br>　　　cout &lt;&lt; n;<br>　　　return 0;<br>　　}<br>　　函数max中首先定义了可变参数表指针ap，而后通过va_start ( ap, num )取得了参数表首地址（赋给了ap），其后的for循环则用来遍历可变参数表。这种遍历方式与我们在数据结构教材中经常看到的遍历方式是类似的。<br>　　函数max看起来简洁明了，但是实际上printf的实现却远比这复杂。max函数之所以看起来简单，是因为：<br>　　(1) max函数可变参数表的长度是已知的，通过num参数传入；<br>　　(2) max函数可变参数表中参数的类型是已知的，都为int型。<br>　　而printf函数则没有这么幸运。首先，printf函数可变参数的个数不能轻易的得到，而可变参数的类型也不是固定的，需由格式字符串进行识别（由%f、%d、%s等确定），因此则涉及到可变参数表的更复杂应用。<br>　　下面我们以实例来分析可变参数表的高级应用。<br><br>　　二. 高级应用<br>　　下面这个程序是我们为某嵌入式系统（该系统中CPU的字长为16位）编写的在屏幕上显示格式字符串的函数DrawText，它的用法类似于 int printf ( const char *format, ... )函数，但其输出的目标为嵌入式系统的液晶显示屏幕（LED）。<br>　　///////////////////////////////////////////////////////////////////////////////<br>　　// 函数名称: DrawText<br>　　// 功能说明: 在显示屏上绘制文字<br>　　// 参数说明: xPos ---横坐标的位置 [0 .. 30]<br>　　// yPos ---纵坐标的位置 [0 .. 64]<br>　　// ... 可以同数字一起显示，需设置标志(%d、%l、%x、%s)<br>　　///////////////////////////////////////////////////////////////////////////////<br>　　extern void DrawText ( BYTE xPos, BYTE yPos, LPBYTE lpStr, ... )<br>　　{<br>　　　BYTE lpData[100]; //缓冲区<br>　　　BYTE byIndex;<br>　　　BYTE byLen;<br>　　　DWORD dwTemp;<br>　　　WORD wTemp;<br>　　　int i;<br>　　　va_list lpParam;<br>　　　memset( lpData, 0, 100);<br>　　　byLen = strlen( lpStr );<br>　　　byIndex = 0;<br>　　　va_start ( lpParam, lpStr );<br>　　　for ( i = 0; i &lt; byLen; i++ )<br>　　　{<br>　　　　if( lpStr[i] != &#8217;%&#8217; ) //不是格式符开始<br>　　　　{<br>　　　　　lpData[byIndex++] = lpStr[i];<br>　　　　}<br>　　　　else<br>　　　　{<br>　　　　　switch (lpStr[i+1])<br>　　　　　{<br>　　　　　　//整型<br>　　　　　　case &#8217;d&#8217;:<br>　　　　　　case &#8217;D&#8217;:<br>　　　　　　　wTemp = va_arg ( lpParam, int );<br>　　　　　　　byIndex += IntToStr( lpData+byIndex, (DWORD)wTemp );<br>　　　　　　　i++;<br>　　　　　　　break;<br>　　　　　　//长整型<br>　　　　　　case &#8217;l&#8217;:<br>　　　　　　case &#8217;L&#8217;:<br>　　　　　　　dwTemp = va_arg ( lpParam, long );<br>　　　　　　　byIndex += IntToStr ( lpData+byIndex, (DWORD)dwTemp );<br>　　　　　　　i++;<br>　　　　　　　break;<br>　　　　　　//16进制（长整型）<br>　　　　　　case &#8217;x&#8217;:<br>　　　　　　case &#8217;X&#8217;:<br>　　　　　　　dwTemp = va_arg ( lpParam, long );<br>　　　　　　　byIndex += HexToStr ( lpData+byIndex, (DWORD)dwTemp );<br>　　　　　　　i++;<br>　　　　　　　break;<br>　　　　　　default:<br>　　　　　　　lpData[byIndex++] = lpStr[i];<br>　　　　　　　break;<br>　　　　　}<br>　　　　}<br>　　　}<br>　　　va_end ( lpParam );<br>　　　lpData[byIndex] = &#8217;#CONTENT#&#8217;;<br>　　　DisplayString ( xPos, yPos, lpData, TRUE);　//在屏幕上显示字符串lpData<br>　　}<br>　　在这个函数中，需通过对传入的格式字符串（首地址为lpStr）进行识别来获知可变参数个数及各个可变参数的类型，具体实现体现在for循环中。譬如，在识别为%d后，做的是va_arg ( lpParam, int )，而获知为%l和%x后则进行的是va_arg ( lpParam, long )。格式字符串识别完成后，可变参数也就处理完了。<br>　　在项目的最初，我们一直苦于不能找到一个好的办法来混合输出字符串和数字，我们采用了分别显示数字和字符串的方法，并分别指定坐标，程序条理被破坏。而且，在混合显示的时候，要给各类数据分别人工计算坐标，我们感觉头疼不已。以前的函数为：<br>　　//显示字符串<br>　　showString ( BYTE xPos, BYTE yPos, LPBYTE lpStr )<br>　　//显示数字<br>　　showNum ( BYTE xPos, BYTE yPos, int num )<br>　　//以16进制方式显示数字<br>　　showHexNum ( BYTE xPos, BYTE yPos, int num )<br>　　最终，我们用DrawText ( BYTE xPos, BYTE yPos, LPBYTE lpStr, ... )函数代替了原先所有的输出函数，程序得到了简化。就这样，兄弟们用得爽翻了。<br><br>　　三. 运行机制探索<br>　　通过第2节我们学会了可变参数表的使用方法，相信喜欢抛根问底的读者还不甘心，必然想知道如下问题：<br>　　（1）为什么按照第2节的做法就可以获得可变参数并对其进行操作？<br>　　（2）C/C++在底层究竟是依靠什么来对这一语法进行支持的，为什么其它语言就不能提供可变参数表呢？<br>　　我们带着这些疑问来一步步进行摸索。<br>　　3.1 调用机制反汇编<br>　　反汇编是研究语法深层特性的终极良策，先来看看2.2节例子中主函数进行max ( 5, 5, 6 ,3 ,8 ,5)调用时的反汇编：<br>　　1. 004010C8 push 5<br>　　2. 004010CA push 8<br>　　3. 004010CC push 3<br>　　4. 004010CE push 6<br>　　5. 004010D0 push 5<br>　　6. 004010D2 push 5<br>　　7. 004010D4 call @ILT+5(max) (0040100a)<br>　　从上述反汇编代码中我们可以看出，C/C++函数调用的过程中：<br>　　第一步：将参数从右向左入栈（第1～6行）；<br>　　第二步：调用call指令进行跳转（第7行）。<br>　　这两步包含了深刻的含义，它说明C/C++默认的调用方式为由调用者管理参数入栈的操作，且入栈的顺序为从右至左，这种调用方式称为_cdecl调用。x86系统的入栈方向为从高地址到低地址，故第1至n个参数被放在了地址递增的堆栈内。在被调用函数内部，读取这些堆栈的内容就可获得各个参数的值，让我们反汇编到max函数的内部：<br>　　int max ( int num, ...)<br>　　{<br>　　1. 00401020 push ebp<br>　　2. 00401021 mov ebp,esp<br>　　3. 00401023 sub esp,50h<br>　　4. 00401026 push ebx<br>　　5. 00401027 push esi<br>　　6. 00401028 push edi<br>　　7. 00401029 lea edi,[ebp-50h]<br>　　8. 0040102C mov ecx,14h<br>　　9. 00401031 mov eax,0CCCCCCCCh<br>　　10. 00401036 rep stos dword ptr [edi]<br>　　va_list ap;<br>　　int m = -0x7FFFFFFF; /* 32系统中最小的整数 */<br>　　11. 00401038 mov dword ptr [ebp-8],80000001h<br>　　va_start ( ap, num );<br>　　12. 0040103F lea eax,[ebp+0Ch]<br>　　13. 00401042 mov dword ptr [ebp-4],eax<br>　　for ( int i= 0; i&lt; num; i++ )<br>　　14. 00401045 mov dword ptr [ebp-0Ch],0<br>　　15. 0040104C jmp max+37h (00401057)<br>　　16. 0040104E mov ecx,dword ptr [ebp-0Ch]<br>　　17. 00401051 add ecx,1<br>　　18. 00401054 mov dword ptr [ebp-0Ch],ecx<br>　　19. 00401057 mov edx,dword ptr [ebp-0Ch]<br>　　20. 0040105A cmp edx,dword ptr [ebp+8]<br>　　21. 0040105D jge max+61h (00401081)<br>　　{<br>　　　int t= va_arg (ap, int);<br>　　　22. 0040105F mov eax,dword ptr [ebp-4]<br>　　　23. 00401062 add eax,4<br>　　　24. 00401065 mov dword ptr [ebp-4],eax<br>　　　25. 00401068 mov ecx,dword ptr [ebp-4]<br>　　　26. 0040106B mov edx,dword ptr [ecx-4]<br>　　　27. 0040106E mov dword ptr [t],edx<br>　　　if ( t &gt; m )<br>　　　　28. 00401071 mov eax,dword ptr [t]<br>　　　　29. 00401074 cmp eax,dword ptr [ebp-8]<br>　　　　30. 00401077 jle max+5Fh (0040107f)<br>　　　　m = t;<br>　　　　31. 00401079 mov ecx,dword ptr [t]<br>　　　　32. 0040107C mov dword ptr [ebp-8],ecx<br>　　　}<br>　　　33. 0040107F jmp max+2Eh (0040104e)<br>　　　va_end (ap);<br>　　　34. 00401081 mov dword ptr [ebp-4],0<br>　　　return m;<br>　　　35. 00401088 mov eax,dword ptr [ebp-8]<br>　　}<br>　　36. 0040108B pop edi<br>　　37. 0040108C pop esi<br>　　38. 0040108D pop ebx<br>　　39. 0040108E mov esp,ebp<br>　　40. 00401090 pop ebp<br>　　41. 00401091 ret<br>　　分析上述反汇编代码，对于一个真正的程序员而言，将是一种很大的享受；而对于初学者，也将使其受益良多。所以请一定要赖着头皮认真研究，千万不要被吓倒！<br>　　行1～10进行执行函数内代码的准备工作，保存现场。第2行对堆栈进行移动；第3行则意味着max函数为其内部局部变量准备的堆栈空间为50h字节；第11行表示把变量n的内存空间安排在了函数内部局部栈底减8的位置（占用4个字节）。<br>　　第12～13行非常关键，对应着va_start ( ap, num )，这两行将第一个可变参数的地址赋值给了指针ap。另外，从第12行可以看出num的地址为ebp+0Ch；从第13行可以看出ap被分配在函数内部局部栈底减4的位置上（占用4个字节）。<br>　　第22～27行最为关键，对应着va_arg (ap, int)。其中，22~24行的作用为将ap指向下一可变参数（可变参数的地址间隔为4个字节，从add eax,4可以看出）；25~27行则取当前可变参数的值赋给变量t。这段反汇编很奇怪，它先移动可变参数指针，再在赋值指令里面回过头来取先前的参数值赋给t（从mov edx,dword ptr [ecx-4]语句可以看出）。Visual C++同学玩得有意思，不知道碰见同样的情况Visual Basic等其它同学怎么玩？<br>　　第36～41行恢复现场和堆栈地址，执行函数返回操作。<br>　　痛苦的反汇编之旅差不多结束了，看了这段反汇编我们总算弄明白了可变参数的存放位置以及它们被读取的方式，顿觉全省轻松！<br>　　2、特殊的调用约定<br>　　除此之外，我们需要了解C/C++函数调用对参数占用空间的一些特殊约定，因为在_cdecl调用协议中，有些变量类型是按照其它变量的尺寸入栈的。<br>　　例如，字符型变量将被自动扩展为一个字的空间，因为入栈操作针对的是一个字。<br>　　参数n实际占用的空间为( ( sizeof(n) + sizeof(int) - 1 ) &amp; ~( sizeof(int) - 1 ) )，这就是第2.1节_INTSIZEOF(v)宏的来历！<br>　　既然如此，前面给出的va_arg ( list, mode )宏为什么玩这么大的飞机就很清楚了。这个问题就留个读者您来分析.<br><br><br><br><a href="http://wp1314.ycool.com/post.3001515.html">http://wp1314.ycool.com/post.3001515.html</a><br>
<img src ="http://www.cppblog.com/maosher/aggbug/118126.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/maosher/" target="_blank">Brandon</a> 2010-06-17 23:52 <a href="http://www.cppblog.com/maosher/archive/2010/06/17/118126.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++中string的一些转换</title><link>http://www.cppblog.com/maosher/archive/2009/05/31/86250.html</link><dc:creator>Brandon</dc:creator><author>Brandon</author><pubDate>Sun, 31 May 2009 04:38:00 GMT</pubDate><guid>http://www.cppblog.com/maosher/archive/2009/05/31/86250.html</guid><wfw:comment>http://www.cppblog.com/maosher/comments/86250.html</wfw:comment><comments>http://www.cppblog.com/maosher/archive/2009/05/31/86250.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/maosher/comments/commentRss/86250.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/maosher/services/trackbacks/86250.html</trackback:ping><description><![CDATA[<span  style="font-family: ������; font-size: 12px; ">这是我上次从这里看到的把它给保存了下来，希望对你有用。&#160;<br>1. c++中string到int的转换&#160;<br>1) 在C标准库里面，使用atoi：&#160;<br><br>#include &lt;cstdlib>&#160;<br>#include &lt;string>&#160;<br><br>std::string text = "152";&#160;<br>int number = std::atoi( text.c_str() );&#160;<br>if (errno == ERANGE) //可能是std::errno&#160;<br>{&#160;<br>//number可能由于过大或过小而不能完全存储&#160;<br>}&#160;<br>else if (errno == ????)&#160;<br>//可能是EINVAL&#160;<br>{&#160;<br>//不能转换成一个数字&#160;<br>}&#160;<br><br>2) 在C++标准库里面，使用stringstream：(stringstream 可以用于各种数据类型之间的转换)&#160;<br><br>#include &lt;sstream>&#160;<br>#include &lt;string>&#160;<br><br>std::string text = "152";&#160;<br>int number;&#160;<br>std::stringstream ss;&#160;<br><br><br>ss &lt; &lt; text;//可以是其他数据类型&#160;<br>ss >> number; //string -> int&#160;<br>if (! ss.good())&#160;<br>{&#160;<br>//错误发生&#160;<br>}&#160;<br><br><br>ss &lt; &lt; number;// int->string&#160;<br>string str = ss.str();&#160;<br>if (! ss.good())&#160;<br>{&#160;<br>//错误发生&#160;<br>}&#160;<br><br>3) 在Boost库里面，使用lexical_cast：&#160;<br><br>#include &lt;boost/lexical_cast.hpp>&#160;<br>#include &lt;string>&#160;<br><br>try&#160;<br>{&#160;<br>std::string text = "152";&#160;<br>int number = boost::lexical_cast &lt; int >( text );&#160;<br>}&#160;<br>catch( const boost::bad_lexical_cast &amp; )&#160;<br>{&#160;<br>//转换失败&#160;<br>}&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160;&#160;<br><br>2.string 转 CString&#160;<br>CString.format(&#8221;%s&#8221;, string.c_str());&#160;<br>用c_str()确实比data()要好；&#160;<br><br><br>3.char 转 CString&#160;<br>CString.format(&#8221;%s&#8221;, char*);&#160;<br><br>4.char 转 string&#160;<br>string s(char *);&#160;<br>只能初始化，在不是初始化的地方最好还是用assign().&#160;<br><br><br>5.string 转 char *&#160;<br>char *p = string.c_str();&#160;<br><br>6.CString 转 string&#160;<br>string s(CString.GetBuffer());&#160;<br>GetBuffer()后一定要ReleaseBuffer(),否则就没有释放缓冲区所占的空间.&#160;<br><br>7.字符串的内容转换为字符数组和C—string&#160;<br>(1)&#160; data(),返回没有&#8221;\0&#8220;的字符串数组&#160;<br>(2)&#160; c_str()，返回有&#8221;\0&#8220;的字符串数组&#160;<br>(3)&#160; copy()&#160;<br><br>8.CString与int、char*、char[100]之间的转换&#160;<br><br>(1) CString互转int&#160;<br><br>将字符转换为整数，可以使用atoi、_atoi64或atol。而将数字转换为CString变量，可以使用CString的Format函数。如&#160;<br>CString s;&#160;<br>int i = 64;&#160;<br>s.Format(&#8221;%d&#8221;, i)&#160;<br>Format函数的功能很强，值得你研究一下。&#160;<br><br>void CStrDlg::OnButton1()&#160;<br>{&#160;<br>&#160; CString&#160;<br>&#160; ss=&#8221;1212.12&#8243;;&#160;<br>&#160; int temp=atoi(ss);&#160;<br>&#160; CString aa;&#160;<br>&#160; aa.Format(&#8221;%d&#8221;,temp);&#160;<br>&#160; AfxMessageBox(&#8221;var is &#8221; + aa);&#160;<br>}&#160;<br><br>(2) CString互转char*&#160;<br><br>///char * TO cstring&#160;<br>CString strtest;&#160;<br>char * charpoint;&#160;<br>charpoint=&#8221;give string a value&#8221;; //?&#160;<br>strtest=charpoint;&#160;<br><br>///cstring TO char *&#160;<br>charpoint=strtest.GetBuffer(strtest.GetLength());&#160;<br><br>(3) 标准C里没有string,char *==char []==string, 可以用CString.Format(&#8221;%s&#8221;,char *)这个方法来将char *转成CString。&#160;<br>&#160; &#160; 要把CString转成char *，用操作符（LPCSTR）CString就可以了。&#160;<br>&#160; &#160; CString转换 char[100]&#160;<br>&#160; char a[100];&#160;<br>&#160; CString str(&#8221;aaaaaa&#8221;);&#160;<br>&#160; strncpy(a,(LPCTSTR)str,sizeof(a));&#160;</span>
<img src ="http://www.cppblog.com/maosher/aggbug/86250.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/maosher/" target="_blank">Brandon</a> 2009-05-31 12:38 <a href="http://www.cppblog.com/maosher/archive/2009/05/31/86250.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>泛型算法</title><link>http://www.cppblog.com/maosher/archive/2009/04/10/79467.html</link><dc:creator>Brandon</dc:creator><author>Brandon</author><pubDate>Fri, 10 Apr 2009 04:27:00 GMT</pubDate><guid>http://www.cppblog.com/maosher/archive/2009/04/10/79467.html</guid><wfw:comment>http://www.cppblog.com/maosher/comments/79467.html</wfw:comment><comments>http://www.cppblog.com/maosher/archive/2009/04/10/79467.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/maosher/comments/commentRss/79467.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/maosher/services/trackbacks/79467.html</trackback:ping><description><![CDATA[<span  style="font-family: Verdana; font-size: 13px; line-height: 19px; "><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">拷贝：<br></p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">copy（）<br>reverse_copy()<br>rotate_copy()<br>remove_copy()&#160; 拷贝不等于某值的元素到另一个序列。<br>remove_copy_if() 拷贝符合条件的到另一个序列。</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">填充和生成：<br>fill()<br>fill_n() 填充序列中的n个元素。<br>generate（）为序列中的每个元素调用gen（）函数。</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">排列：<br>next_permuttion() 后一个排列。<br>prev_permutation()</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">partition() 划分，将满足条件的元素移动到序列的前面。<br>stable_partition()</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">查找和替换：<br>find（）<br>binary_search() 在一个已经有顺序的序列上查找。<br>find_if()<br>search() 检查第二个序列是否在第一个序列中出现，且顺序相同。</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">删除：注意必须调用erase（）来真正删除<br>remove（）<br>unique（）删除相邻重复元素，最好现排序。</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">合并序列：<br>merge（）</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">数值算法：<br>accumulate（） 对序列的每个元素进行运算后求和。<br>transform（） 也可以对每个元素进行运算。<br>计数：<br>size（）总个数。<br>count（）等于某值的元素个数。</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">adjacent_difference 序列中的后一个减前与他相邻的前一个得到新的序列。</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; ">adiacent_find</p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "><span lang="EN-US"><span><span style="font: normal normal normal 7pt/normal 'Times New Roman'; ">&#160;</span></span></span><font size="2"><strong><span lang="EN-US"><font face="Tahoma">accumlate</font>&#160;</span></strong><span style="font-family: 宋体; ">：</span>&#160;<span lang="EN-US"><font face="Tahoma">iterator</font>&#160;</span><span style="font-family: 宋体; ">对标志的序列中的元素之和，加到一个由</span>&#160;<span lang="EN-US"><font face="Tahoma">init</font>&#160;</span><span style="font-family: 宋体; ">指定的初始值上。重载的版本不再做加法，而是传进来的二元操作符被应用到元素上。</span>&#160;</font><br></p><p style="margin-top: 10px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; "><span lang="EN-US"><strong><font face="Tahoma" size="2">adjacent_different</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：创建一个新序列，该序列的每个新值都代表了当前元素与上一个元素的差。重载版本用指定的二元操作计算相邻元素的差。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">adjacent_find</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：在</span>&#160;<span lang="EN-US">iterator</span>&#160;<span style="font-family: 宋体; ">对标志的元素范围内，查找一对相邻的重复元素，如果找到返回一个</span>&#160;<span lang="EN-US">ForwardIterator</span>&#160;<span style="font-family: 宋体; ">，指向这对元素的第一个元素。否则返回</span>&#160;<span lang="EN-US">last</span>&#160;<span style="font-family: 宋体; ">。重载版本使用输入的二元操作符代替相等的判断。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">binary_search</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：在有序序列中查找</span>&#160;<span lang="EN-US">value</span>&#160;<span style="font-family: 宋体; ">，如果找到返回</span>&#160;<span lang="EN-US">true</span>&#160;<span style="font-family: 宋体; ">。重载的版本使用指定的比较函数对象或者函数指针来判断相等。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">copy</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：复制序列。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">copy_backward</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：除了元素以相反的顺序被拷贝外，别的和</span>&#160;<span lang="EN-US">copy</span>&#160;<span style="font-family: 宋体; ">相同。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">count</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：利用等于操作符，把标志范围类的元素与输入的值进行比较，并返回相等元素的个数。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">count_if</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：对于标志范围类的元素，应用输入的操作符，并返回结果为</span>&#160;<span lang="EN-US">true</span>&#160;<span style="font-family: 宋体; ">的次数。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">equal</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：如果两个序列在范围内的元素都相等，则</span>&#160;<span lang="EN-US">equal</span>&#160;<span style="font-family: 宋体; ">返回</span>&#160;<span lang="EN-US">true</span>&#160;<span style="font-family: 宋体; ">。重载版本使用输入的操作符代替了默认的等于操作符。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">equal_range</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：返回一对</span>&#160;<span lang="EN-US">iterator</span>&#160;<span style="font-family: 宋体; ">，第一个</span>&#160;<span lang="EN-US">iterator</span>&#160;<span style="font-family: 宋体; ">表示由</span>&#160;<span lang="EN-US">lower_bound</span>&#160;<span style="font-family: 宋体; ">返回的</span>&#160;<span lang="EN-US">iterator</span>&#160;<span style="font-family: 宋体; ">，第二个表示由</span>&#160;<span lang="EN-US">upper_bound</span>&#160;<span style="font-family: 宋体; ">返回的</span>&#160;<span lang="EN-US">iterator</span><span style="font-family: 宋体; ">值。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">fill</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：将输入的值的拷贝赋给范围内的每个元素。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">fill_n</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：将输入的值赋值给</span>&#160;<span lang="EN-US">first</span>&#160;<span style="font-family: 宋体; ">到</span>&#160;<span lang="EN-US">frist+n</span>&#160;<span style="font-family: 宋体; ">范围内的元素。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">find</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：利用底层元素的等于操作符，对范围内的元素与输入的值进行比较。当匹配时，结束搜索，返回该元素的一个</span>&#160;<span lang="EN-US">InputIterator</span>&#160;<span style="font-family: 宋体; ">。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">find_if</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：使用输入的函数替代了等于操作符执行了</span>&#160;<span lang="EN-US">find</span>&#160;<span style="font-family: 宋体; ">。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">find_end</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：在范围内查找&#8220;由输入的另外一个</span>&#160;<span lang="EN-US">iterator</span>&#160;<span style="font-family: 宋体; ">对标志的第二个序列&#8221;的最后一次出现。重载版本中使用了用户输入的操作符替代等于操作。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">find_first_of</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：在范围内查找&#8220;由输入的另外一个</span>&#160;<span lang="EN-US">iterator</span>&#160;<span style="font-family: 宋体; ">对标志的第二个序列&#8221;中的任意一个元素的第一次出现。重载版本中使用了用户自定义的操作符。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">for_each</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：依次对范围内的所有元素执行输入的函数。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">generate</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：通过对输入的函数</span>&#160;<span lang="EN-US">gen</span>&#160;<span style="font-family: 宋体; ">的连续调用来填充指定的范围。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">generate_n</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：填充</span>&#160;<span lang="EN-US">n</span>&#160;<span style="font-family: 宋体; ">个元素。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">includes</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：判断</span>&#160;<span lang="EN-US">[first1, last1)</span>&#160;<span style="font-family: 宋体; ">的一个元素是否被包含在另外一个序列中。使用底层元素的</span>&#160;<span lang="EN-US">&lt;=</span>&#160;<span style="font-family: 宋体; ">操作符，重载版本使用用户输入的函数。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">inner_product</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：对两个序列做内积</span>&#160;<span lang="EN-US">(</span>&#160;<span style="font-family: 宋体; ">对应的元素相乘，再求和</span>&#160;<span lang="EN-US">)</span>&#160;<span style="font-family: 宋体; ">，并将内积加到一个输入的的初始值上。重载版本使用了用户定义的操作。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">inner_merge</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：合并两个排过序的连续序列，结果序列覆盖了两端范围，重载版本使用输入的操作进行排序。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">iter_swap</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：交换两个</span>&#160;<span lang="EN-US">ForwardIterator</span>&#160;<span style="font-family: 宋体; ">的值。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">lexicographical_compare</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：比较两个序列。重载版本使用了用户自定义的比较操作。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">lower_bound</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：返回一个</span>&#160;<span lang="EN-US">iterator</span>&#160;<span style="font-family: 宋体; ">，它指向在范围内的有序序列中可以插入指定值而不破坏容器顺序的第一个位置。重载函数使用了自定义的比较操作。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">max</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：返回两个元素中的较大的一个，重载版本使用了自定义的比较操作。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">max_element</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：返回一个</span>&#160;<span lang="EN-US">iterator</span>&#160;<span style="font-family: 宋体; ">，指出序列中最大的元素。重载版本使用自定义的比较操作。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">min</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：两个元素中的较小者。重载版本使用自定义的比较操作。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">min_element</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：类似与</span>&#160;<span lang="EN-US">max_element</span>&#160;<span style="font-family: 宋体; ">，不过返回最小的元素。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">merge</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：合并两个有序序列，并存放到另外一个序列中。重载版本使用自定义的比较。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">mismatch</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：并行的比较两个序列，指出第一个不匹配的位置，它返回一对</span>&#160;<span lang="EN-US">iterator</span>&#160;<span style="font-family: 宋体; ">，标志第一个不匹配的元素位置。如果都匹配，返回每个容器的</span>&#160;<span lang="EN-US">last</span>&#160;<span style="font-family: 宋体; ">。重载版本使用自定义的比较操作。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">next_permutation</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：取出当前范围内的排列，并将其重新排序为下一个排列。重载版本使用自定义的比较操作。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">nth_element</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：将范围内的序列重新排序，使所有小于第</span>&#160;<span lang="EN-US">n</span>&#160;<span style="font-family: 宋体; ">个元素的元素都出现在它前面，而大于它的都出现在后面，重载版本使用了自定义的比较操作。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">partial_sort</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：对整个序列做部分排序，被排序元素的个数正好可以被放到范围内。重载版本使用自定义的比较操作。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">partial_sort_copy</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：与</span>&#160;<span lang="EN-US">partial_sort</span>&#160;<span style="font-family: 宋体; ">相同，除了将经过排序的序列复制到另外一个容器。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">partial_sum</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：创建一个新的元素序列，其中每个元素的值代表了范围内该位置之前所有元素之和。重载版本使用了自定义操作替代加法。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">partition</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：对范围内元素重新排序，使用输入的函数，把计算结果为</span>&#160;<span lang="EN-US">true</span>&#160;<span style="font-family: 宋体; ">的元素都放在结果为</span>&#160;<span lang="EN-US">false</span>&#160;<span style="font-family: 宋体; ">的元素之前。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">prev_permutation</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：取出范围内的序列并将它重新排序为上一个序列。如果不存在上一个序列则返回</span>&#160;<span lang="EN-US">false</span>&#160;<span style="font-family: 宋体; ">。重载版本使用自定义的比较操作。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">random_shuffle</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：对范围内的元素随机调整次序。重载版本输入一个随机数产生操作。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">remove</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：删除在范围内的所有等于指定的元素，注意，该函数并不真正删除元素。内置数组不适合使用</span>&#160;<span lang="EN-US">remove</span>&#160;<span style="font-family: 宋体; ">和</span>&#160;<span lang="EN-US">remove_if</span>&#160;<span style="font-family: 宋体; ">函数。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">remove_copy</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：将所有不匹配的元素都复制到一个指定容器，返回的</span>&#160;<span lang="EN-US">OutputIterator</span>&#160;<span style="font-family: 宋体; ">指向被拷贝的末元素的下一个位置。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">remove_if</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：删除所有范围内输入操作结果为</span>&#160;<span lang="EN-US">true</span>&#160;<span style="font-family: 宋体; ">的元素。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">remove_copy_if</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：将所有不匹配的元素拷贝到一个指定容器。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">replace</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：将范围内的所有等于</span>&#160;<span lang="EN-US">old_value</span>&#160;<span style="font-family: 宋体; ">的元素都用</span>&#160;<span lang="EN-US">new_value</span>&#160;<span style="font-family: 宋体; ">替代。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">replace_copy</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：与</span>&#160;<span lang="EN-US">replace</span>&#160;<span style="font-family: 宋体; ">类似，不过将结果写入另外一个容器。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">replace_if</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：将范围内的所有操作结果为</span>&#160;<span lang="EN-US">true</span>&#160;<span style="font-family: 宋体; ">的元素用新值替代。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">replace_copy_if</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：类似与</span>&#160;<span lang="EN-US">replace_if</span>&#160;<span style="font-family: 宋体; ">，不过将结果写入另外一个容器。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">reverse</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：将范围内元素重新按反序排列。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">reverse_copy</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：类似与</span>&#160;<span lang="EN-US">reverse</span>&#160;<span style="font-family: 宋体; ">，不过将结果写入另外一个容器。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">rotate</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：将范围内的元素移到容器末尾，由</span>&#160;<span lang="EN-US">middle</span>&#160;<span style="font-family: 宋体; ">指向的元素成为容器第一个元素。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">rotate_copy</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：类似与</span>&#160;<span lang="EN-US">rotate</span>&#160;<span style="font-family: 宋体; ">，不过将结果写入另外一个容器。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">search</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：给出了两个范围，返回一个</span>&#160;<span lang="EN-US">iterator</span>&#160;<span style="font-family: 宋体; ">，指向在范围内第一次出现子序列的位置。重载版本使用自定义的比较操作。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">search_n</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：在范围内查找</span>&#160;<span lang="EN-US">value</span>&#160;<span style="font-family: 宋体; ">出现</span>&#160;<span lang="EN-US">n</span>&#160;<span style="font-family: 宋体; ">次的子序列。重载版本使用自定义的比较操作。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">set_difference</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：构造一个排过序的序列，其中的元素出现在第一个序列中，但是不包含在第二个序列中。重载版本使用自定义的比较操作。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">set_intersection</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：构造一个排过序的序列，其中的元素在两个序列中都存在。重载版本使用自定义的比较操作。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">set_symmetric_difference</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：构造一个排过序的序列，其中的元素在第一个序列中出现，但是不出现在第二个序列中。重载版本使用自定义的比较操作。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">set_union</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：构造一个排过序的序列，它包含两个序列中的所有的不重复元素。重载版本使用自定义的比较操作。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">sort</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：以升序重新排列范围内的元素，重载版本使用了自定义的比较操作。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">stable_partition</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：与</span>&#160;<span lang="EN-US">partition</span>&#160;<span style="font-family: 宋体; ">类似，不过它不保证保留容器中的相对顺序。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">stable_sort</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：类似与</span>&#160;<span lang="EN-US">sort</span>&#160;<span style="font-family: 宋体; ">，不过保留相等元素之间的顺序关系。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">swap</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：交换存储在两个对象中的值。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">swap_range</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：将在范围内的元素与另外一个序列的元素值进行交换。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">transform</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：将输入的操作作用在范围内的每个元素上，并产生一个新的序列。重载版本将操作作用在一对元素上，另外一个元素来自输入的另外一个序列。结果输出到指定的容器。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">unique</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：清除序列中重复的元素，和</span>&#160;<span lang="EN-US">remove</span>&#160;<span style="font-family: 宋体; ">类似，它也不能真正的删除元素。重载版本使用了自定义的操作。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">unique_copy</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：类似与</span>&#160;<span lang="EN-US">unique</span>&#160;<span style="font-family: 宋体; ">，不过它把结果输出到另外一个容器。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">upper_bound</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：返回一个</span>&#160;<span lang="EN-US">iterator</span>&#160;<span style="font-family: 宋体; ">，它指向在范围内的有序序列中插入</span>&#160;<span lang="EN-US">value</span>&#160;<span style="font-family: 宋体; ">而不破坏容器顺序的最后一个位置，该位置标志了一个大于</span>&#160;<span lang="EN-US">value</span>&#160;<span style="font-family: 宋体; ">的值。重载版本使用了输入的比较操作。</span>&#160;</font></font><span lang="EN-US"><br></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">堆算法：</span>&#160;<span lang="EN-US">C++</span>&#160;<span style="font-family: 宋体; ">标准库提供的是</span>&#160;<span lang="EN-US">max-heap</span>&#160;<span style="font-family: 宋体; ">。一共由以下</span>&#160;<span lang="EN-US">4</span>&#160;<span style="font-family: 宋体; ">个泛型堆算法。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">make_heap</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：把范围内的元素生成一个堆。重载版本使用自定义的比较操作。</font>&#160;</span><span lang="EN-US"><br><strong><font face="Tahoma" size="2">pop_heap</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：并不是真正的把最大元素从堆中弹出，而是重新排序堆。它把</span>&#160;<span lang="EN-US">first</span>&#160;<span style="font-family: 宋体; ">和</span>&#160;<span lang="EN-US">last-1</span>&#160;<span style="font-family: 宋体; ">交换，然后重新做成一个堆。可以使用容器的</span>&#160;<span lang="EN-US">back</span>&#160;<span style="font-family: 宋体; ">来访问被&#8220;弹出&#8220;的元素或者使用</span>&#160;<span lang="EN-US">pop_back</span>&#160;<span style="font-family: 宋体; ">来真正的删除。重载版本使用自定义的比较操作。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">push_heap</font>&#160;</strong></span><font face="Tahoma"><font size="2"><span style="font-family: 宋体; ">：假设</span>&#160;<span lang="EN-US">first</span>&#160;<span style="font-family: 宋体; ">到</span>&#160;<span lang="EN-US">last-1</span>&#160;<span style="font-family: 宋体; ">是一个有效的堆，要被加入堆的元素在位置</span>&#160;<span lang="EN-US">last-1</span>&#160;<span style="font-family: 宋体; ">，重新生成堆。在指向该函数前，必须先把元素插入容器后。重载版本使用指定的比较。</span>&#160;</font></font><span lang="EN-US"><br><strong><font face="Tahoma" size="2">sort_heap</font>&#160;</strong></span><span style="font-family: 宋体; "><font face="Tahoma" size="2">：对范围内的序列重新排序，它假设该序列是个有序的堆。重载版本使用自定义的比较操作。</font></span></p></span>
<img src ="http://www.cppblog.com/maosher/aggbug/79467.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/maosher/" target="_blank">Brandon</a> 2009-04-10 12:27 <a href="http://www.cppblog.com/maosher/archive/2009/04/10/79467.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>详解typedef 的用法</title><link>http://www.cppblog.com/maosher/archive/2009/04/10/79416.html</link><dc:creator>Brandon</dc:creator><author>Brandon</author><pubDate>Fri, 10 Apr 2009 01:20:00 GMT</pubDate><guid>http://www.cppblog.com/maosher/archive/2009/04/10/79416.html</guid><wfw:comment>http://www.cppblog.com/maosher/comments/79416.html</wfw:comment><comments>http://www.cppblog.com/maosher/archive/2009/04/10/79416.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/maosher/comments/commentRss/79416.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/maosher/services/trackbacks/79416.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: typedef 的用法&#160;--摘自一位cnblog的一位大侠&#160;用途一：&#160;定义一种类型的别名，而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如：&#160;char* pa, pb;&#160;&#160;//&#160;这多数不符合我们的意图，它只声明了一个指向字符变量的指针，&#160;//&#160;和一个字符变量；&#160;以下则可行：&#160;t...&nbsp;&nbsp;<a href='http://www.cppblog.com/maosher/archive/2009/04/10/79416.html'>阅读全文</a><img src ="http://www.cppblog.com/maosher/aggbug/79416.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/maosher/" target="_blank">Brandon</a> 2009-04-10 09:20 <a href="http://www.cppblog.com/maosher/archive/2009/04/10/79416.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>类型转换</title><link>http://www.cppblog.com/maosher/archive/2009/04/03/78794.html</link><dc:creator>Brandon</dc:creator><author>Brandon</author><pubDate>Fri, 03 Apr 2009 03:10:00 GMT</pubDate><guid>http://www.cppblog.com/maosher/archive/2009/04/03/78794.html</guid><wfw:comment>http://www.cppblog.com/maosher/comments/78794.html</wfw:comment><comments>http://www.cppblog.com/maosher/archive/2009/04/03/78794.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/maosher/comments/commentRss/78794.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/maosher/services/trackbacks/78794.html</trackback:ping><description><![CDATA[
<span style="font-family: 'lucida Grande'; font-size: 14px; line-height: 23px;">显式类型转换又被称之为 强制类型转换。&#160;<br>C&#160;&#160;&#160;&#160; 风格： (type-id)&#160;<br>C++风格： static_cast、dynamic_cast、reinterpret_cast、和const_cast&#160;<br>C风格的强制类型转换是最好不要用的，最好是使用标准的C++风格的转换符。&#160;<br><br><br><strong>static_cast</strong>&#160;<br><strong>用法：</strong>static_cast &lt; type-id > ( expression )&#160;<br><strong>说明：</strong>该运算符把expression转换为type-id类型，但没有运行时类型检查来保证转换的安全性。&#160;<br><strong>主要用法：</strong>&#160;<br>用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换（把子类的指针或引用转换成基类表示）是安全的；进行下行转换（把基类指针或引用转换成子类指针或引用）时，由于没有动态类型检查，所以是不安全的。&#160;<br>用于基本数据类型之间的转换，如把int转换成char，把int转换成enum。这种转换的安全性也要开发人员来保证。&#160;<br>把void指针转换成目标类型的指针(不安全!!)&#160;<br>把任何类型的表达式转换成void类型。&#160;<br>注意：static_cast不能转换掉expression的const、volitale、或者__unaligned属性。&#160;<br><br><strong>dynamic_cast</strong>&#160;<br><strong>用法：</strong>dynamic_cast &lt; type-id > ( expression )&#160;<br><strong>说明：</strong>该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *；如果type-id是类指针类型，那么expression也必须是一个指针，如果type-id是一个引用，那么expression也必须是一个引用。&#160;<br>dynamic_cast主要用于类层次间的上行转换和下行转换，还可以用于类之间的交叉转换。&#160;<br>在类层次间进行上行转换时，dynamic_cast和static_cast的效果是一样的；&#160;<br>在进行下行转换时，dynamic_cast具有类型检查的功能，比static_cast更安全。&#160;<br><br><strong>reinterpret_cast&#160;<br>用法：</strong>reinterpret_cast&lt;type-id> (expression)&#160;<br><strong>说明：</strong>type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。&#160;<br>它可以把一个指针转换成一个整数，也可以把一个整数转换成一个指针（先把一个指针转换成一个整数，&#160;<br>在把该整数转换成原类型的指针，还可以得到原先的指针值）。&#160;<br>该运算符的用法比较多。&#160;<br><br><strong>const_cast</strong>&#160;<br><strong>用法：</strong>const_cast&lt;type_id> (expression)&#160;<br><strong>说明：</strong>该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外， type_id和expression的类型是一样的。&#160;<br>常量指针被转化成非常量指针，并且仍然指向原来的对象；&#160;<br>常量引用被转换成非常量引用，并且仍然指向原来的对象；常量对象被转换成非常量对象。<br></span><img src ="http://www.cppblog.com/maosher/aggbug/78794.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/maosher/" target="_blank">Brandon</a> 2009-04-03 11:10 <a href="http://www.cppblog.com/maosher/archive/2009/04/03/78794.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>string 类</title><link>http://www.cppblog.com/maosher/archive/2009/02/08/73200.html</link><dc:creator>Brandon</dc:creator><author>Brandon</author><pubDate>Sun, 08 Feb 2009 02:42:00 GMT</pubDate><guid>http://www.cppblog.com/maosher/archive/2009/02/08/73200.html</guid><wfw:comment>http://www.cppblog.com/maosher/comments/73200.html</wfw:comment><comments>http://www.cppblog.com/maosher/archive/2009/02/08/73200.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/maosher/comments/commentRss/73200.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/maosher/services/trackbacks/73200.html</trackback:ping><description><![CDATA[
<div style="padding-right: 5px; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left-color: rgb(204, 204, 204); width: 98%; word-break: break-all; padding-top: 4px; background-color: rgb(238, 238, 238); "><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">class&#160;String&#160;<br><img id="Codehighlighter1_14_240_Open_Image" onclick="this.style.display='none'; Codehighlighter1_14_240_Open_Text.style.display='none'; Codehighlighter1_14_240_Closed_Image.style.display='inline'; Codehighlighter1_14_240_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_14_240_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_14_240_Closed_Text.style.display='none'; Codehighlighter1_14_240_Open_Image.style.display='inline'; Codehighlighter1_14_240_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"><img src="http://www.cppblog.com/Images/dot.gif">{&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">public:&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;String(const&#160;char&#160;*str&#160;=&#160;NULL);&#160;//&#160;普通构造函数&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;String(const&#160;String&#160;&amp;other);&#160;//&#160;拷贝构造函数&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;~&#160;String(void);&#160;//&#160;析构函数&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;String&#160;&amp;&#160;operate&#160;=(const&#160;String&#160;&amp;other);&#160;//&#160;赋值函数&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">private:&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;char&#160;*m_data;&#160;//&#160;用于保存字符串&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">};&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">//&#160;String&#160;的析构函数&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">String::~String(void)&#160;<br><img id="Codehighlighter1_285_350_Open_Image" onclick="this.style.display='none'; Codehighlighter1_285_350_Open_Text.style.display='none'; Codehighlighter1_285_350_Closed_Image.style.display='inline'; Codehighlighter1_285_350_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_285_350_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_285_350_Closed_Text.style.display='none'; Codehighlighter1_285_350_Open_Image.style.display='inline'; Codehighlighter1_285_350_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"><img src="http://www.cppblog.com/Images/dot.gif">{&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;delete&#160;[]&#160;m_data;//&#160;由于m_data&#160;是内部数据类型,也可以写成delete&#160;m_data;&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">//&#160;String&#160;的普通构造函数&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">String::String(const&#160;char&#160;*str)&#160;<br><img id="Codehighlighter1_406_660_Open_Image" onclick="this.style.display='none'; Codehighlighter1_406_660_Open_Text.style.display='none'; Codehighlighter1_406_660_Closed_Image.style.display='inline'; Codehighlighter1_406_660_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_406_660_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_406_660_Closed_Text.style.display='none'; Codehighlighter1_406_660_Open_Image.style.display='inline'; Codehighlighter1_406_660_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"><img src="http://www.cppblog.com/Images/dot.gif">{&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;if(str==NULL)&#160;<br><img id="Codehighlighter1_432_513_Open_Image" onclick="this.style.display='none'; Codehighlighter1_432_513_Open_Text.style.display='none'; Codehighlighter1_432_513_Closed_Image.style.display='inline'; Codehighlighter1_432_513_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_432_513_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_432_513_Closed_Text.style.display='none'; Codehighlighter1_432_513_Open_Image.style.display='inline'; Codehighlighter1_432_513_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&#160;&#160;&#160;&#160;<img src="http://www.cppblog.com/Images/dot.gif">{&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;m_data&#160;=&#160;new&#160;char[1];&#160;//&#160;若能加NULL&#160;判断则更好&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;*m_data&#160;=&#160;'\0';&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top">&#160;&#160;&#160;&#160;}&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;else&#160;<br><img id="Codehighlighter1_530_657_Open_Image" onclick="this.style.display='none'; Codehighlighter1_530_657_Open_Text.style.display='none'; Codehighlighter1_530_657_Closed_Image.style.display='inline'; Codehighlighter1_530_657_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_530_657_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_530_657_Closed_Text.style.display='none'; Codehighlighter1_530_657_Open_Image.style.display='inline'; Codehighlighter1_530_657_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&#160;&#160;&#160;&#160;<img src="http://www.cppblog.com/Images/dot.gif">{&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;int&#160;length&#160;=&#160;strlen(str);&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;m_data&#160;=&#160;new&#160;char[length+1];&#160;//&#160;若能加NULL&#160;判断则更好&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;strcpy(m_data,&#160;str);&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top">&#160;&#160;&#160;&#160;}&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">//&#160;拷贝构造函数&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">String::String(const&#160;String&#160;&amp;other)&#160;<br><img id="Codehighlighter1_712_841_Open_Image" onclick="this.style.display='none'; Codehighlighter1_712_841_Open_Text.style.display='none'; Codehighlighter1_712_841_Closed_Image.style.display='inline'; Codehighlighter1_712_841_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_712_841_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_712_841_Closed_Text.style.display='none'; Codehighlighter1_712_841_Open_Image.style.display='inline'; Codehighlighter1_712_841_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"><img src="http://www.cppblog.com/Images/dot.gif">{&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;int&#160;length&#160;=&#160;strlen(other.m_data);&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;m_data&#160;=&#160;new&#160;char[length+1];&#160;//&#160;若能加NULL&#160;判断则更好&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;strcpy(m_data,&#160;other.m_data);&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">//&#160;赋值函数&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">String&#160;&amp;&#160;String::operate&#160;=(const&#160;String&#160;&amp;other)&#160;<br><img id="Codehighlighter1_904_1208_Open_Image" onclick="this.style.display='none'; Codehighlighter1_904_1208_Open_Text.style.display='none'; Codehighlighter1_904_1208_Closed_Image.style.display='inline'; Codehighlighter1_904_1208_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_904_1208_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_904_1208_Closed_Text.style.display='none'; Codehighlighter1_904_1208_Open_Image.style.display='inline'; Codehighlighter1_904_1208_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"><img src="http://www.cppblog.com/Images/dot.gif">{&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;//&#160;(1)&#160;检查自赋值&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;if(this&#160;==&#160;&amp;other)&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;return&#160;*this;&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;//&#160;(2)&#160;释放原有的内存资源&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;delete&#160;[]&#160;m_data;&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;//&#160;(3)分配新的内存资源,并复制内容&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;int&#160;length&#160;=&#160;strlen(other.m_data);&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;m_data&#160;=&#160;new&#160;char[length+1];&#160;//&#160;若能加NULL&#160;判断则更好&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;strcpy(m_data,&#160;other.m_data);&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;//&#160;(4)返回本对象的引用&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&#160;&#160;&#160;&#160;return&#160;*this;&#160;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></div><img src ="http://www.cppblog.com/maosher/aggbug/73200.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/maosher/" target="_blank">Brandon</a> 2009-02-08 10:42 <a href="http://www.cppblog.com/maosher/archive/2009/02/08/73200.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网摘（一）</title><link>http://www.cppblog.com/maosher/archive/2009/02/08/73193.html</link><dc:creator>Brandon</dc:creator><author>Brandon</author><pubDate>Sat, 07 Feb 2009 17:00:00 GMT</pubDate><guid>http://www.cppblog.com/maosher/archive/2009/02/08/73193.html</guid><wfw:comment>http://www.cppblog.com/maosher/comments/73193.html</wfw:comment><comments>http://www.cppblog.com/maosher/archive/2009/02/08/73193.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/maosher/comments/commentRss/73193.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/maosher/services/trackbacks/73193.html</trackback:ping><description><![CDATA[
保持统一的接口，而具体行为依照对象而定，不同的对象有不同的行为，这个就是对多态的简单解释.。<br><br><br>具体在C++语言中，多态通过指针和引用来表现。<br>即接口使用父类的指针或引用来表明抽象的统一的接口，而行为根据父类指针或引用所指向具体子类对象，不同的对象表现出不同的行为，此乃C++实现多态的风格，具体来说我们在编程的时候需要使用指向父类的指针或者引用，然后在子类中改写父类中的虚函数，最后再把子类对象赋值到父类指针或引用上。<br>&#160;<br>C++的虚函数实际上采用散列表的数据结构实现..<img src ="http://www.cppblog.com/maosher/aggbug/73193.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/maosher/" target="_blank">Brandon</a> 2009-02-08 01:00 <a href="http://www.cppblog.com/maosher/archive/2009/02/08/73193.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>