﻿<?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/ichenq/category/11288.html</link><description>程序不过是梦，
生于无形无象的禅中，
我们只是那做梦的人。</description><language>zh-cn</language><lastBuildDate>Mon, 18 Apr 2011 04:53:25 GMT</lastBuildDate><pubDate>Mon, 18 Apr 2011 04:53:25 GMT</pubDate><ttl>60</ttl><item><title>侃一侃vc的std::string</title><link>http://www.cppblog.com/ichenq/archive/2011/04/02/vs-std-string.html</link><dc:creator>johnny chan</dc:creator><author>johnny chan</author><pubDate>Sat, 02 Apr 2011 14:51:00 GMT</pubDate><guid>http://www.cppblog.com/ichenq/archive/2011/04/02/vs-std-string.html</guid><wfw:comment>http://www.cppblog.com/ichenq/comments/143317.html</wfw:comment><comments>http://www.cppblog.com/ichenq/archive/2011/04/02/vs-std-string.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ichenq/comments/commentRss/143317.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ichenq/services/trackbacks/143317.html</trackback:ping><description><![CDATA[那天心血来潮敲下了这坨代码：<br /><div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); 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: rgb(0, 0, 0);">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, 255);">sizeof</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">std::string</span><span style="color: rgb(0, 0, 0);">) &lt;&lt; endl;</span></div>我的平台是XP+VC9.0，运行结果是32，不知道为什么要那么多，于是在源代码里捣鼓了一番，许久之后终于有了一点眉目，下面是我的一些总结。<br /><br /><br />一，结构布局<br />string的原型是<br /><br /><div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); 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: rgb(0, 0, 0);">typedef basic_string</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);">, char_traits</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">, allocator</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);">;</span></div><br />它是basic_string一个typedef，首先来看basic_string的类层次结构：<br /><br />_Container_base_secure<br />       /\<br />       |<br />_String_base<br />       /\<br />       |<br />_String_val<br />       /\<br />       |<br />basic_string<br /><br /><br />_Container_base_secure里有一个_Iterator_base类型的指针成员_Myfirstiter，得占4个字节，_String_base没有数据成员，_String_val里有一个_Alval类型（一个allocator）的成员_Alty，没有数据成员，只占用1个字节，加上padding，也就是4个字节，basic_string有3个数据成员，一个union占16个字节，两个跟长度相关的整型变量各4个字节。所有类都不含虚函数，布局如下：<br /><br /><div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); 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: rgb(0, 0, 0);">_Container_base_secure<br />    _Myfirstiter：_Iterator_base</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">  (</span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);"> bytes)<br /><br />_String_base (nop)<br /><br />_String_val<br />      _Alty：_Alval  (</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">byte</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, 0);">3</span><span style="color: rgb(0, 0, 0);"> bytes padding)<br />      <br />basic_string<br />    _Bx        :   _Bxty       (</span><span style="color: rgb(0, 0, 0);">16</span><span style="color: rgb(0, 0, 0);"> bytes)<br />    _Mysize :   size_type   (</span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);"> bytes)<br />    _Myres ：  size_type   (</span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);"> bytes)</span></div><br /><br /><br />这个是basic_string的union:<br /><div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); 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: rgb(0, 0, 0);">enum{  _BUF_SIZE = 16 / sizeof (_Elem) &lt; 1 ? 1 : 16 / sizeof(_Elem)};<br />union _Bxty<br />{ <br />    _Elem</span><span style="color: rgb(0, 0, 0);">  _Buf[_BUF_SIZE];<br />    _Elem</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> _Ptr;<br />} _Bx;<br /><br /></span></div>通过这个union可以看出vc的std::string在字符串长度较小的时候会使用一个栈上缓冲区（_Bxty::_Buf）来保存字符串内容，如果字符串长度超过了某个范围则会使用allocator分配动态内存(_Bxty::_Ptr)，_BUF_SIZE控制着这个范围值，_Buf缓冲区始终是16个字节大小。可以看出，vc的std::string没有使用通用Copy-On-Write技术，因为它没有reference count成员。那么vc采用的这个技术对于字符串的使用效率在实际使用中表现如何呢？<br /><br />下面是一段测试拷贝不同字符串长度的代码:<br /><div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); 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: rgb(0, 0, 0);">#include </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">windows.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />#include </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">stdio.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />#include </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">iostream</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />#include </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />#include </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">vector</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><br /></span><span style="color: rgb(0, 0, 255);">using</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">namespace</span><span style="color: rgb(0, 0, 0);"> std;<br /><br />template </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">size_t N</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> test_string()<br />{<br />    </span><span style="color: rgb(0, 0, 255);">const</span><span style="color: rgb(0, 0, 0);"> size_t loop </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">1000000</span><span style="color: rgb(0, 0, 0);">; // 一百万次<br />    <br />    // 预先分配好内存<br />    vector</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"> vec;<br />    vec.resize(loop);<br />    <br />    </span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"> szbuf[N] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> {};<br />    memset(szbuf, </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);">'</span><span style="color: rgb(0, 0, 0);">, N </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">);<br /><br />    // 计算拷贝时间<br />    size_t time </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> GetTickCount();<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);"> i </span><span style="color: rgb(0, 0, 0);">=</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);">; i </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> loop; </span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);">i)<br />    {<br />        vec[i] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> szbuf;<br />    }<br />    time </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> GetTickCount() </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);"> time;<br /><br />    printf(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">buffer size: %u, loop: %u, used %u ms\n</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, N, loop, time);<br />}<br /><br /><br /></span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> main(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> argc, </span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> argv[])<br />{<br />    test_string</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">8</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">();<br />    test_string</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">12</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">();<br />    test_string</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">16</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">();<br />    test_string</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">20</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">();<br />    test_string</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">24</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">();<br />    test_string</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">32</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">();<br /><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>编译使用release版全默认参数，结果如下：<br /><br />buffer size: 4, loop: 1000000, used 78 ms<br />buffer size: 8, loop: 1000000, used 94 ms<br />buffer size: 12, loop: 1000000, used 93 ms<br />buffer size: 16, loop: 1000000, used 94 ms<br />buffer size: 20, loop: 1000000, used 422 ms<br />buffer size: 24, loop: 1000000, used 422 ms<br />buffer size: 32, loop: 1000000, used 438 ms<br /><br /><br />在字符串(包含0结尾字符)小于16个字节的时候消耗的时间都很低而且几乎一致(94ms)，而一旦超过了16个字节消耗时间则迅速增加，变成了422ms（近5倍）。可以看出，如果使用长度较小的字符串，在涉及大量拷贝处理的时候，vc这个技巧的效率还是挺高的。<br /><br /><br />下面是相同代码采用使用了Copy-On-Write技术的GNU std::string的运行结果（Ubuntu + gcc4.4 + -O2参数）：<br /><br />buffer size: 8, loop: 1000000, used 140 ms<br />buffer size: 12, loop: 1000000, used 119 ms<br />buffer size: 16, loop: 1000000, used 140 ms<br />buffer size: 20, loop: 1000000, used 126 ms<br />buffer size: 24, loop: 1000000, used 154 ms<br />buffer size: 32, loop: 1000000, used 129 ms<br /><br /><br />速度增长很平均，在16字节以下的时候用时比vc多，但是超过16字节后效率比vc高（细节没去研究）。<br /><br /><br />二，虚析构函数<br /><br />basic_string和它的基类_Container_base_secure的析构函数都不是virutual function，这在继承的时候会有副作用，先看下面这段代码：<br /><div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); 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: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> mystring : </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> std::</span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);"><br />{<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, 0);">~</span><span style="color: rgb(0, 0, 0);">mystring()<br />    {<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);">"</span><span style="color: rgb(0, 0, 0);">dctor</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> endl;<br />    }<br />};<br /><br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> main()<br />{<br />    std::</span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> pstr </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> mystring();<br />    delete pstr;  // ~mystring()没有被调用<br />}</span></div><br />没有虚函数所以析构函数无法动态绑定，上面的代码运行到delete时将直接调用std::string的析构函数，而不会去找mystring的析构函数。如果~mystring涉及到资源释放的话，那么无疑上面的代码将导致泄漏。<br /><br />还有一点值得一提的就是对std::string或包含std::string的对象实施ZeroMemory<br /><br />虽然大多数合格的C++程序员都知道不应该对非POD对象实施ZeroMomory，但是在工程实际中确实有这样的代码，而且他们运行的很正常(vc++下)，这是为什么呢？我试图做一个简单解释。<br /><br />如上所述，std::string的继承体系里没有virtual function，对象布局里也就没有vptr，而且整个继承体系都采用的是单继承，bptr又省了（参考Lippman的&lt;Inside C++ Object Model&gt;），所以std::string对象的布局全是它的自身的数据成员，_Container_base_secure的_Myfirstiter是指针成员，本身在初始化时就需要置零，_String_val的_Alval成员是个allocator，只有函数不包含数据，调用时也就不必传this指针，所以给它置零不会有副作用，basic_string指针本身的三个成员分别是缓冲区，字符串长度和预留长度，初始化时将它们置零也是没有副作用的。所以对std::string进行ZeroMemory操作的代码依然运行的很正常。<br /><br /><br /><br /><br /><br /><br /><br /><br /><img src ="http://www.cppblog.com/ichenq/aggbug/143317.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ichenq/" target="_blank">johnny chan</a> 2011-04-02 22:51 <a href="http://www.cppblog.com/ichenq/archive/2011/04/02/vs-std-string.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有趣的条件运算符</title><link>http://www.cppblog.com/ichenq/archive/2011/03/28/interesting-condition-operator.html</link><dc:creator>johnny chan</dc:creator><author>johnny chan</author><pubDate>Mon, 28 Mar 2011 15:02:00 GMT</pubDate><guid>http://www.cppblog.com/ichenq/archive/2011/03/28/interesting-condition-operator.html</guid><wfw:comment>http://www.cppblog.com/ichenq/comments/142898.html</wfw:comment><comments>http://www.cppblog.com/ichenq/archive/2011/03/28/interesting-condition-operator.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ichenq/comments/commentRss/142898.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ichenq/services/trackbacks/142898.html</trackback:ping><description><![CDATA[
		<br />一，缘起<br /><br />平常都是把条件运算符当作简化if/else代码行数的另一种形式，今天偶然写下了下面这砣代码，就是让第二个和第三个表达式的具有不同类型，看看sizeof的结果：<br /><div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); 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: rgb(0, 0, 0);">#include </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">iostream</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><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);"> n </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">sizeof</span><span style="color: rgb(0, 0, 0);">(( </span><span style="color: rgb(0, 0, 255);">true</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, 0);">3</span><span style="color: rgb(0, 0, 0);"> : </span><span style="color: rgb(0, 0, 0);">3.14</span><span style="color: rgb(0, 0, 0);">);    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 不同的类型</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    printf(“Type size: </span><span style="color: rgb(0, 0, 0);">%</span><span style="color: rgb(0, 0, 0);">d\n”, n);<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><br />结果是:  Type size: 8<br /><br /><br />二，细节<br /><br /><br />一个<a href="http://en.wikipedia.org/wiki/?:">条件操作符</a>是下面这样的形式:<br /><br />exp1 ? exp2 : exp3<br /><br />表达式exp1总是会被求值。exp2和exp3是否被执行依赖于exp1的值，如果exp1为真则exp2会被求值，否则exp3被求值。<br /><br /><br /><a href="http://en.wikipedia.org/wiki/Side_effect_%28computer_science%29">Side Effect</a>:<br /><br />在执行exp2或者exp3之前，exp1的所有side effect必须全部求值或者更新完成，因为条件操作符的第一个操作数求值之后就是一个<a href="http://en.wikipedia.org/wiki/Sequence_point">sequence point</a>。如果exp2和exp3都有side effect，那么只有一个会被求值。<br /><br /><br /><br />返回类型：<br /><br />条件操作符的返回类型取决于exp2和exp3类型，编译器会检查exp2（可能是一个class type）能否转换为exp3或者exp3能否转换为exp2，如果两个都不满足，编译器就会抛出一个错误。<br /><br /><br /><br />三，实践<br /><br />只要exp2或expr3能转换为对方的类型，那么条件操作符就可以通过编译器，如果它们之间没有能够转换的规则，自然过不了编译器这一关，如下面这行代码:<br /><br />sizeof(true ? “text” : 3.14);    // error<br /><br />sizeof(true ? “text” : 0);    // OK, bug or feature?<br /><br /><br />为了利用C++给我们提供的强类型支持，我们应该在实践中让exp2和exp3的类型保持一致。<br /><br />另外，<a href="http://www.boost.org/doc/libs/1_46_1/doc/html/foreach.html">BOOST_FOREACH</a>里面用到了条件操作符的这个技巧来萃取容器表达式类型，同时避免对表达式求值，以此达到对rvalue的完美支持，其中的代码如下：<br /><br /><div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); 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: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 类型包装器</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);"><br />template</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> T </span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">struct</span><span style="color: rgb(0, 0, 0);"> type2type {};<br /><br /><br /><br /></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 转换T到type2type&lt;t&gt;</span><span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);"><br />template</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> T </span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />type2type</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> T </span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"> encode_type( T </span><span style="color: rgb(0, 0, 255);">const</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);"> t )<br />{<br />    </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> type2type</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> T </span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">();<br />}<br /><br /></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 定义了到any2type&lt;t&gt;的转换</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">struct</span><span style="color: rgb(0, 0, 0);"> any_type<br />{<br />    template</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> T </span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">operator</span><span style="color: rgb(0, 0, 0);"> type2type</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> T </span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"> () </span><span style="color: rgb(0, 0, 255);">const</span><span style="color: rgb(0, 0, 0);"><br />    {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> type2type</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> T </span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">();<br />    }<br />};<br /><br /></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 将表达式的类型转换为type2type&lt; expression&gt;，并避免对 expression求值</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">#define</span><span style="color: rgb(0, 0, 0);"> ENCODED_TYPEOF( expression )         </span><span style="color: rgb(0, 0, 0);">( </span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">?</span><span style="color: rgb(0, 0, 0);"> any_type() : encode_type( expression ) )</span></div><br /><br /><br />ENCODED_TYPEOF(expression)会被展开为 (true ? any_type() : encode_type(expression))，exp2的类型为any_type，exp3的类型为type2type&lt;expression&gt;，两个表达式的类型要一致，type2type&lt;expression&gt;又不能转换为any_type，所以只有给any_type定义一个转换操作符，让any_type能够转换为type2type&lt;expression&gt;。<br /><br />最后我们得到ENCODE_TYPEOF(expression)的类型为type2type&lt; expression&gt;，并且没有对 expression求值。<br /><br /><br /><br /><br />参考:<br /><br /><a href="http://drdobbs.com/cpp/184401310">http://drdobbs.com/cpp/184401310</a><br /><a title=" Conditional Operator" href="http://geeksforgeeks.org/?p=9205">http://geeksforgeeks.org/?p=9205</a><br /><a title="Foreach Dedux" href="http://www.artima.com/cppsource/foreach2.html">http://www.artima.com/cppsource/foreach2.html</a><br /><br /><br /><img src ="http://www.cppblog.com/ichenq/aggbug/142898.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ichenq/" target="_blank">johnny chan</a> 2011-03-28 23:02 <a href="http://www.cppblog.com/ichenq/archive/2011/03/28/interesting-condition-operator.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C的可变参数列表</title><link>http://www.cppblog.com/ichenq/archive/2009/06/21/varialbe-list-in-c.html</link><dc:creator>johnny chan</dc:creator><author>johnny chan</author><pubDate>Sun, 21 Jun 2009 15:34:00 GMT</pubDate><guid>http://www.cppblog.com/ichenq/archive/2009/06/21/varialbe-list-in-c.html</guid><wfw:comment>http://www.cppblog.com/ichenq/comments/88245.html</wfw:comment><comments>http://www.cppblog.com/ichenq/archive/2009/06/21/varialbe-list-in-c.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ichenq/comments/commentRss/88245.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ichenq/services/trackbacks/88245.html</trackback:ping><description><![CDATA[一，<br />
当我们的程序调用函数的时候，系统会首先将函数的参数按照从右自左的顺序压入函数的栈中。如果底层的C语言实现让函数参数在内存中连续存储，那么我们只需要知道当前参数的地址，就可以依次访问参数列表中的其他参数。<br /><br />
这里为了举例方便，假设传递的3个都是int类型的参数。代码：<br /><br /><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, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">fun: 打印n后面参数的值</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> fun(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> n, <img src="http://www.cppblog.com/images/dot.gif" />);<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);"> par1 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">128</span><span style="color: rgb(0, 0, 0);">;<br />    </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> par2 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">256</span><span style="color: rgb(0, 0, 0);">;<br />    </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> par3 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">512</span><span style="color: rgb(0, 0, 0);">;<br />    fun(par1, par2, par3 );<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 />}<br /><br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> fun(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> par1, <img src="http://www.cppblog.com/images/dot.gif" />)<br />{<br />    </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);"> p </span><span style="color: rgb(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);">par1;             </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">获取par1的地址   </span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    printf(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">%d \n</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, 0);">p);      </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">打印par2的值</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    printf(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">%d \n</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, 0);">p);      </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">打印par3的值</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">}</span></div><br /><br /><br />
C默认的函数调用规范是__cdecl,也就是所有参数从右到左依次入栈，严格的fun声明应该是:<br /><br />
void __cdecl fun(int n, ...);<br /><br /><br />
由于入栈顺序是从右向左，所以main给传递的par1,par2和par3的入栈顺序是：<br />
push      par3<br />
push       par2<br />
push       par1<br /><br />
当然汇编代码(wintel)更可能是：<br />
mov           eax,dword ptr [par3] <br />
push          eax  <br />
mov           ecx,dword ptr [par2] <br />
push          ecx  <br />
mov           edx,dword ptr [par1] <br />
push          edx<br /><br />
最后再call fun,执行函数体的代码。<br /><br />
先压栈的参数会放在高地址，因为栈是由上往下生长的，所以par1，par2，par3在内存中的顺序将会是：<br />
0xFE6C         par3 <br />
0xFE70          par2<br />
0xFE74          par1<br /><br />
地址是假设，但距离应该是sizeof(int)的值(4个字节)。<br /><br />
另外，标准库里的printf一族的库函数(sprintf, fprintf)那样接受可变参数个数的函数也只有用cdecl才能够实现。假设有下面一行语句：<br /><br />
printf("%d %d %d \n", m, n, k);<br /><br />
可以看到它是通过把参数的个数和类型保存在第一个参数来实现正确寻址的。格式符%d指定了要读取的类型，而格式符的数目指定了传递参数的个数。这就是为什么printf("%d %d \n", m, n, k)可以成功执行，而printf("%d %d %d \n", m,
n)会失败的原因。传递的参数多于需要处理的数目时可以忽略掉，但是少于需要处理的数目时就访问越界了。<br /><br /><br /><br /><br />
二，<br /><br />
我们通常会使用C语言的varargs宏来编写支持可变参数列表的函数，在ANSI C标准里，这些宏包含在<stdarg.h>头文件里。<br /><br />
下面再分析一下varargs宏，增加varargs宏后的代码：<br /><br /><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);">#include </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">stdio.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />#include </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">stdarg.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /><br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> __cdecl fun(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> n, <img src="http://www.cppblog.com/images/dot.gif" />);<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);"> par1 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">128</span><span style="color: rgb(0, 0, 0);">;<br />    </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> par2 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">256</span><span style="color: rgb(0, 0, 0);">;<br />    </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> par3 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">512</span><span style="color: rgb(0, 0, 0);">;<br />    fun(par1, par2, par3 );<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 />}<br /><br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> fun(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> n, <img src="http://www.cppblog.com/images/dot.gif" />)<br />{<br />    va_list ap;<br />    va_start(ap, n);<br />    printf(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">%d \n</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, va_arg(ap, </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">));<br />    printf(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">%d \n</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, va_arg(ap, </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">));<br />    va_end(ap);<br />}</span></div><br /><br />
在Microsoft为VC提供的实现中，可以看到这样的定义：<br /><br /><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);">#define</span><span style="color: rgb(0, 0, 0);"> _ADDRESSOF(v)   ( &amp;(v) )</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">#define</span><span style="color: rgb(0, 0, 0);"> _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) &amp; ~(sizeof(int) - 1) )</span><span style="color: rgb(0, 0, 0);"><br />typedef </span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> va_list;<br /></span><span style="color: rgb(0, 0, 255);">#define</span><span style="color: rgb(0, 0, 0);"> va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">#define</span><span style="color: rgb(0, 0, 0);"> va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">#define</span><span style="color: rgb(0, 0, 0);"> va_end(ap)      ( ap = (va_list)0 )</span></div><br /><br />
va_list        一个char型指针，每次单个字节寻址。 <br />
va_start       通过_INTSIZEOF计算类型的大小，并让ap获得v后面参数对象的地址           <br />
va_arg         ap指向参数列表中ap下一个参数对象，并返回ap之前指向的t类型参数对象<br /><br /><br />
将va_list等宏还原后会更明白一点：<br /><br /><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);"> fun(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> par1, <img src="http://www.cppblog.com/images/dot.gif" />)<br />{<br />    </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> par2, par3;<br />    </span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">   ap;                         </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">va_list ap;</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    ap </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> (</span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(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);">par1 </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);">;      </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">va_start(ap, par1);</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    par2 </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, 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);">)(ap</span><span style="color: rgb(0, 0, 0);">+=</span><span style="color: rgb(0, 0, 0);">4</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, 0);">4</span><span style="color: rgb(0, 0, 0);">); </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">m = va_arg(ap, int);</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    par3 </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, 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);">)(ap</span><span style="color: rgb(0, 0, 0);">+=</span><span style="color: rgb(0, 0, 0);">4</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, 0);">4</span><span style="color: rgb(0, 0, 0);">); </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">m = va_arg(ap, int);</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    ap </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> (</span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);">*</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);">;                   </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">va_end(ap);</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">}</span></div><br /><br />
根据这个实现，va_arg的第二个参数若为char, short则会被转换为int类型，若为float则会转换为doule类型，这是因为_INTSIZEOF宏的返回值(4或8)的原因，毕竟宏用C来做泛型还是不如C++的模板来的好。<br /><br /><br /><br /><br />
三，<br /><br />
根据标准库提供的va_list我们可以实现自己的能接受可变参数的列表的函数，下面以Win32API中的MessageBox作为试验。<br />
在windows程序设计中有时候也需要输出一些调试信息，但是这个时候如果根据在控制台下的编程习惯使用printf()函数来实现将信息输出到窗口的
话是比较麻烦的，这样可以选择一个最简单的Windows窗口函数MessageBox。但是MessageBox()的参数类型是字符串，所以我们需要
对它做一些格式化。这就需要用到标准库的vsprintf函数(<font color="#ff0000">这里</font>)。<br /><br /><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);">#include </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">stdio.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">       </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> vsprintf()</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">#include </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">stdarg.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">      </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> va_list, va_start(), va_end()</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">#include </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">windows.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">     </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> MessageBoxA()</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);"><br /><br /></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> my_messagebox(</span><span style="color: rgb(0, 0, 255);">const</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> format, <img src="http://www.cppblog.com/images/dot.gif" />)<br />{<br />    </span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);">        buffer[MAX_PATH] </span><span style="color: rgb(0, 0, 0);">=</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);">};</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">260个字节的缓冲</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    va_list     ap;   <br />    va_start(ap, format);<br />    vsprintf(buffer, format, ap);<br />    va_end(ap);<br />    ::MessageBoxA(NULL, buffer, </span><span style="color: rgb(0, 0, 0);">""</span><span style="color: rgb(0, 0, 0);">, MB_OK);</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">ANSCII版本的MessageBox()</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">}</span></div><br /><br /><br /></stdarg.h><img src ="http://www.cppblog.com/ichenq/aggbug/88245.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ichenq/" target="_blank">johnny chan</a> 2009-06-21 23:34 <a href="http://www.cppblog.com/ichenq/archive/2009/06/21/varialbe-list-in-c.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>