﻿<?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++博客-OwnWaterloo</title><link>http://www.cppblog.com/ownwaterloo/</link><description /><language>zh-cn</language><lastBuildDate>Wed, 08 Apr 2026 18:11:50 GMT</lastBuildDate><pubDate>Wed, 08 Apr 2026 18:11:50 GMT</pubDate><ttl>60</ttl><item><title>C与C++的细微区别——省略形式参数名</title><link>http://www.cppblog.com/ownwaterloo/archive/2009/04/26/omit_parameter_name.html</link><dc:creator>OwnWaterloo</dc:creator><author>OwnWaterloo</author><pubDate>Sun, 26 Apr 2009 07:01:00 GMT</pubDate><guid>http://www.cppblog.com/ownwaterloo/archive/2009/04/26/omit_parameter_name.html</guid><wfw:comment>http://www.cppblog.com/ownwaterloo/comments/81117.html</wfw:comment><comments>http://www.cppblog.com/ownwaterloo/archive/2009/04/26/omit_parameter_name.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/ownwaterloo/comments/commentRss/81117.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ownwaterloo/services/trackbacks/81117.html</trackback:ping><description><![CDATA[一、C与C++的细微区别<br><br>在函数声明中：<br>无论是C还是在C++，都<strong>可以省略</strong>形式参数名。<br>但是，通常都<strong><span style="COLOR: red">不</span>建议</strong>省略形式参数名。<br><br>在函数定义中：<br>1. 当需要使用形式参数的时候，显然，必须给形式参数命名。<br><br>2. 当不需要使用形式参数的时候，C与C++有微小差异：<br>—— <strong>C不能省略形式参数名</strong>， <strong style="COLOR: red">即使</strong>不使用。<br>—— <strong>C++可以省略形式参数名</strong>，<strong style="COLOR: red">如果</strong>不使用。<br>—— 并且在C++中，如果给不使用的形式参数命名，可能会得到一个<strong>警告</strong>。<br><br>
<hr width="80%">
<br>二、示例：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;greeting_omit(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;name);<br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;greeting_unuse(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;name);<br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;greeting_nowarning(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;name);<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;greeting_omit(</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;greeting_unuse(</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;greeting_nowarning(</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)getchar();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div>
<br>
<hr width="80%">
<br>三、三个函数分别实现如下：<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 三、1<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;greeting_omit(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">hello&nbsp;world\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>}</span></div>
<br>——在C中是错误：<br>1. msvc :<br>error C2055: expected formal parameter list, not a type list<br>error C2055: 应输入形参表，而不是类型表<br><br>2. gcc : （报错更清晰一些）<br>error: parameter name omitted<br>错误： 省略参数名<br><br>——在C++中正确，且无警告。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 三、2<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;greeting_unuse(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;name)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">hello&nbsp;Cherrie\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>}</span></div>
<br>在C和C++中都正确，但可能得到一个警告：<br>1. msvc :<br>warning C4100: 'name' : unreferenced formal parameter<br>warning C4100: &#8220;name&#8221;: 未引用的形参<br><br>2. gcc :<br>warning: unused parameter 'name'<br>警告： 未使用的参数&#8216;name&#8217;<br><br>在gcc中，打开这个警告的选项是<strong>-Wunused-parameter</strong>。<br>该选项包含在-Wall中。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 三、3<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;greeting_nowarning(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;name)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)name;<br>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">hello&nbsp;OwnWaterloo\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>}</span></div>
<br>在C和C++中都正确，并且无警告。<br><br>
<hr width="90%">
<br>相关链接：<br><br>——示例代码<br><a href="http://immature.googlecode.com/svn/trunk/iMmature/sample/omit_parameter_name">http://immature.googlecode.com/svn/trunk/iMmature/sample/omit_parameter_name</a><br><br>
<hr width="90%">
<br><a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="Creative Commons License" src="http://i.creativecommons.org/l/by-nc-sa/2.5/cn/88x31.png"></a><br>本<span rel="dc:type" href="http://purl.org/dc/dcmitype/Text" xmlns:dc="http://purl.org/dc/elements/1.1/">作品</span>采用<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license>知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议</a>进行许可。 <br><br>转载请注明 ：<br>文章作者 - OwnWaterloo<br>发表时间 - 2009年04月26日<br>原文链接 - <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/26/omit_parameter_name.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/26/omit_parameter_name.html</a> 
<img src ="http://www.cppblog.com/ownwaterloo/aggbug/81117.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ownwaterloo/" target="_blank">OwnWaterloo</a> 2009-04-26 15:01 <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/26/omit_parameter_name.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>main函数中省略返回语句</title><link>http://www.cppblog.com/ownwaterloo/archive/2009/04/26/omit_return_in_main.html</link><dc:creator>OwnWaterloo</dc:creator><author>OwnWaterloo</author><pubDate>Sun, 26 Apr 2009 06:37:00 GMT</pubDate><guid>http://www.cppblog.com/ownwaterloo/archive/2009/04/26/omit_return_in_main.html</guid><wfw:comment>http://www.cppblog.com/ownwaterloo/comments/81116.html</wfw:comment><comments>http://www.cppblog.com/ownwaterloo/archive/2009/04/26/omit_return_in_main.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/ownwaterloo/comments/commentRss/81116.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ownwaterloo/services/trackbacks/81116.html</trackback:ping><description><![CDATA[<p>一、依据<br><br>C++标准规定：main函数可以省略返回语句，等效于返回0。<br><br>5. A return statement in main has the effect of leaving the main function (destroying any objects with automatic storage duration) and calling exit with the return value as the argument.<br>If control reaches the end of main without encountering a return statement, the effect is that of executing<br>return 0;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——ISO C++03 3.6.1 Main function p44/72<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——ISO C++98 3.6.1 Main function p43/69<br><br>注意：<br>1. main函数的返回类型是<strong style="COLOR: #0000ff">int</strong>， 不是void或者其他类型。<br>2. 该规则<strong>仅仅</strong>对main函数适用。<br>3. 对其他函数，如果省略返回值， 将得到一个<strong>警告</strong>。<br>4. 应该<strong>避免</strong>3的情况。<br><br><br>
<hr width="80%">
<br>二、&nbsp;示例<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二、1. 一个合法的最小化的完整C++程序如下：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()&nbsp;{}</span></div>
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二、2. 省略的确切含义<br><br>同时，标准中的用语是很<strong>考究</strong>的：<br>&#8220;当控制到达main结束处时没有遇到return语句，效果与返回0相同&#8221;。<br><br>即是说，标准规定的是&#8220;对省略return的<strong style="COLOR: #ff0000">分支</strong>，认为返回0&#8221;。<br>同时，标准也允许<strong>其他分支</strong>含有返回语句。<br>如下：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;[])&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">switch</span><span style="COLOR: #000000">&nbsp;(argc)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;error,&nbsp;should&nbsp;passing&nbsp;argument</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;parse&nbsp;arguments</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">default</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">:&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;parser&nbsp;argv[2]</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">:&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;parser&nbsp;argv[1]</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;do&nbsp;some&nbsp;work<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;control&nbsp;reaches&nbsp;<strong style="COLOR: #ff0000">here</strong></span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">}</span></div>
<br>没有输入命令行参数时， 返回一个错误。<br>其他情况，当控制达到main的<strong>结尾</strong>处时，效果同return 0;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二、3. 对于其他函数，没有这种&#8220;优待&#8221;<br>如：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;not_main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(argc</span><span style="COLOR: #000000">&lt;=</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>}<br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;[])&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;not_main(argc);<br>}</span></div>
<br>not_main无疑将得到一个警告。<br>程序在没有输入命令行参数时的返回值将<strong><span style="COLOR: #ff0000">无法</span>预知</strong>。<br><br>
<hr width="80%">
<br>三、验证<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 三、1. ERRORLEVEL<br><br>windows下，可以通过 %<strong>ERRORLEVEL</strong>% 查询上一次程序返回值。<br><br>结果与判断相吻合：<br>1. minimalist有<strong>确定</strong>的返回值0<br>2. omit_return_in_main有<strong>确定</strong>的返回值-1或0<br>3. 对omit_return_in_other<br>3.1 有命令行参数时，返回值<strong>确定</strong>为0。<br>3.2 无命令行参数时，返回值<strong><span style="COLOR: #ff0000">无法</span>预知</strong>。
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 三、2 汇编代码<br><br>更严谨的验证方法是查看汇编代码。<br><br>可以看到，在minimalist与omit_return_in_main的main函数中都有将eax置0的代码。<br>在omit_return_in_other中的not_main函数中，没有这样的代码。</p>
<p><br>
<hr width="80%">
<br>四、&nbsp;例外<br><br><strong>VC6</strong>在这点上与标准不符。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 四、1. 对omit_return_in_main，它给出的警告：<br><br>warning C4715: 'main' : not all control paths return a value<br><br>说明它在这点上与标准不符。<br>显然，在有命令行参数的时候，程序结果<strong><span style="COLOR: #ff0000">无法</span>预知</strong>。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 四、2. 对minimalist，它给出的警告很搞笑：<br><br>warning C4508: 'main' : function should return a value; <strong>'void' return type <span style="COLOR: #ff0000">assumed</span></strong><br><br>暴露出它另一个<strong>与标准不符</strong>的地方——main返回void。<br>显然，任何情况下，程序结果都<strong>无法预知</strong>。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 四、3. 对omit_return_in_other，是程序员的错误。<br><br><br>
<hr width="80%">
<br>五、 实践<br><br>不知道为什么C++标准在这里开一个&#8220;后门&#8221;。<br>——C++在许多地方都是很<strong>严谨</strong>的。<br><br>在实际应用中，尽量不要采用这一特性， 因为：<br>1. 旧编译器不支持<br>2. C不支持——如果希望main能同时按C语言编译的话<br><br>对于<strong>演示</strong>用的C++代码，与主题无关的代码行能省则省，则可以使用这一特性。<br>比如：C++标准中的示例代码几乎都采用了这一特性。<br>由此可得出，C++标准在这里开后门的原因是——让C++标准更薄^_^<br><br>
<hr width="90%">
<br>相关链接：<br><br>——示例代码<br><a href="http://immature.googlecode.com/svn/trunk/iMmature/sample/omit_return_in_main">http://immature.googlecode.com/svn/trunk/iMmature/sample/omit_return_in_main<br><br></a>
<hr width="90%">
<p><br><a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="Creative Commons License" src="http://i.creativecommons.org/l/by-nc-sa/2.5/cn/88x31.png"></a><br>本<span xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://purl.org/dc/dcmitype/Text" rel="dc:type">作品</span>采用<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license>知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议</a>进行许可。 <br><br>转载请注明 ：<br>文章作者 - OwnWaterloo<br>发表时间 - 2009年04月26日<br>原文链接 - <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/26/omit_return_in_main.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/26/omit_return_in_main.html</a></p>
<img src ="http://www.cppblog.com/ownwaterloo/aggbug/81116.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ownwaterloo/" target="_blank">OwnWaterloo</a> 2009-04-26 14:37 <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/26/omit_return_in_main.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>可变长参数列表误区与陷阱——va_arg不可接受的类型</title><link>http://www.cppblog.com/ownwaterloo/archive/2009/04/21/unacceptable_type_in_va_arg.html</link><dc:creator>OwnWaterloo</dc:creator><author>OwnWaterloo</author><pubDate>Tue, 21 Apr 2009 15:41:00 GMT</pubDate><guid>http://www.cppblog.com/ownwaterloo/archive/2009/04/21/unacceptable_type_in_va_arg.html</guid><wfw:comment>http://www.cppblog.com/ownwaterloo/comments/80655.html</wfw:comment><comments>http://www.cppblog.com/ownwaterloo/archive/2009/04/21/unacceptable_type_in_va_arg.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/ownwaterloo/comments/commentRss/80655.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ownwaterloo/services/trackbacks/80655.html</trackback:ping><description><![CDATA[实现一个有可变长参数列表函数的时候，会使用到stdarg.h（这里不讨论varargs.h）中提供的宏。<br><br>例如，我们要实现一个简易的my_printf：<br>1. 它只返回void， 不记录输出的字符数目<br>2. 它只接受"%d"按整数输出、"%c"按字符输出、"%%"输出'%'本身<br>如下：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdarg.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;my_printf(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;fmt,&nbsp;...&nbsp;)<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">va_list</span>&nbsp;ap;<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff00ff">va_start</span>(ap,fmt);&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;用最后一个具有参数的类型的参数去初始化ap&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;(;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">fmt;</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">fmt)<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;如果不是控制字符&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">fmt</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;putchar(</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">fmt);&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;直接输出&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">continue</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;如果是控制字符，查看下一字符&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">fmt;<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">\0</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">==*</span><span style="COLOR: #000000">fmt)&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;如果是结束符&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;这是一个错误&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">switch</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">fmt)<br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">:&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;连续2个'%'输出1个'%'&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">25</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;putchar(</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">26</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">27</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">d</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">:&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;按照int输出&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">28</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">29</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;下一个参数是int，取出&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">30</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;<span style="COLOR: #ff00ff">va_arg</span>(ap,</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">31</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%d</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,i);<br></span><span style="COLOR: #008080">32</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">33</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">34</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">c</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">:&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;按照字符输出&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">35</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br></span><span style="COLOR: #008080">36</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">*&nbsp;<span style="COLOR: #ff0000">但是，下一个参数是char吗</span></span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">37</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;&nbsp;<span style="COLOR: #ff0000">可以这样取出吗</span>？&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">38</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;c&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;<span style="COLOR: #ff00ff">va_arg</span>(ap,</span><span style="COLOR: #ff0000"><strong>char</strong></span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">39</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%c</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,c);<br></span><span style="COLOR: #008080">40</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">41</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">43</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">44</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">45</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff00ff">va_end</span>(ap);&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;<strong style="COLOR: #ff0000">释放</strong>ap—— <strong><font color=#ff0000>必须！</font></strong>&nbsp;见<strong>相关链接</strong></span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">46</span>&nbsp;<span style="COLOR: #000000">}</span></div>
<br><br>这与《C++程序设计语言》中的一道练习题很类似。<br>——需要支持"%c"控制符<br><br>在《C++程序设计语言-题解》中，给出了一个答案（中文p65页）。<br>但是， <strong>如同上面的代码一样</strong>，它们都是<strong style="COLOR: #ff0000">错误</strong>的！<br><br><br>
<hr width="80%">
<br><br>简单的说，我们用<span style="COLOR: #ff00ff">va_arg</span>(<span style="COLOR: #666699">ap</span>,<span style="COLOR: #0000ff">type</span>)取出一个参数的时候，<br><strong><span style="COLOR: #0000ff">type</span><span style="COLOR: #ff0000">绝</span>对不能为</strong>以下类型：<br>——<span style="COLOR: #0000ff"><strong>char</strong></span>、<span style="COLOR: #0000ff">signed</span> <span style="COLOR: #0000ff"><strong>char</strong></span>、<span style="COLOR: #0000ff">unsigned</span> <span style="COLOR: #0000ff"><strong>char</strong></span><br>——<span style="COLOR: #0000ff"><strong>short</strong></span>、<span style="COLOR: #0000ff">unsigned</span> <span style="COLOR: #0000ff"><strong>short</strong></span><br>——<span style="COLOR: #0000ff">signed</span> <span style="COLOR: #0000ff"><strong>short</strong></span>、<span style="COLOR: #0000ff"><strong>short</strong></span> <span style="COLOR: #0000ff">int</span>、<span style="COLOR: #0000ff">signed</span> <span style="COLOR: #0000ff"><strong>short</strong></span> <span style="COLOR: #0000ff">int</span>、<span style="COLOR: #0000ff">unsigned</span> <span style="COLOR: #0000ff"><strong>short</strong></span> <span style="COLOR: #0000ff">int</span><br>——<span style="COLOR: #0000ff"><strong>float</strong></span><br><br><br>一个简单的理由是：<br>——<strong>调用者<span style="COLOR: #ff0000">绝对不</span>会</strong>向<span style="COLOR: #993300">my_printf</span><strong>传递</strong>以上类型的<strong>实际参数</strong>。<br><br><br>在C语言中，调用一个不带原型声明的函数时：<br>调用者会对<strong>每个</strong>参数执行&#8220;默认实际参数<strong>提升</strong>(default argument <strong>promotions</strong>)&#8221;。<br><br>同时，对可变长参数列表<strong>超出最后一个</strong>有<strong>类型声明的形式参数</strong>之后的<strong>每一个实际参数</strong>，也将执行上述提升工作。<br>提升工作如下：<br>——float类型的实际参数将提升到double<br>——char、short和相应的signed、unsigned类型的实际参数提升到int<br>——如果int不能存储原值，则提升到unsigned int<br><br>然后，调用者将<strong>提升后</strong>的参数<strong>传递</strong>给被调用者。<br>所以，my_printf是<strong>绝对无法接收到</strong>上述类型的实际参数的。<br><br><br>
<hr width="80%">
<br>上面的代码的38与39行，应该改为：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;c&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;<span style="COLOR: #ff00ff">va_arg</span>(ap,</span><span style="COLOR: #0000ff"><strong>int</strong></span><span style="COLOR: #000000">);<br>printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%c</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,c);</span></div>
<br>同理， 如果需要使用short和float， 也应该这样：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;s&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">)va_arg(ap,</span><span style="COLOR: #0000ff"><strong>int</strong></span><span style="COLOR: #000000">);<br></span><span style="COLOR: #0000ff">float</span><span style="COLOR: #000000">&nbsp;f&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">float</span><span style="COLOR: #000000">)va_arg(ap,</span><span style="COLOR: #0000ff"><strong>double</strong></span><span style="COLOR: #000000">);</span></div>
<br>这也是printf族函数没有用于short和float的控制符的原因。<br><br>
<hr width="90%">
<br>附录：<br><br>在《C语言程序设计》对可变长参数列表的相关章节中，并没有提到这个陷阱。<br>但是有提到默认实际参数提升的规则：<br><br>在没有函数原型的情况下，char与short类型都将被转换为int类型，float类型将被转换为double类型。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——《C语言程序设计》第2版 &nbsp;2.7 类型转换 p36<br><br><br><br>在其他一些书籍中，也有提到这个规则：<br><br><br>事情很清楚，如果一个参数没有声明，编译器就没有信息去对它执行标准的类型检查和转换。<br>在这种情况下，一个char或short将作为int传递，float将作为double传递。<br>这些做未必是程序员所期望的。<br>脚注：这些都是由C语言继承来的标准提升。<br>对于由省略号表示的参数，其实际参数在传递之前总执行这些提升（如果它们属于需要提升的类型），将提升后的值传递给有关的函数。——译者注<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——《C++程序设计语言》第3版-特别版 7.6 p138<br><br>&#8230;&#8230; float类型的参数会自动转换为double类型，short或char类型的参数会自动转换为int类型 &#8230;&#8230;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——《C陷阱与缺陷》 4.4 形参、实参与返回值 p73<br><br><br>这里有一个陷阱需要避免：<br>va_arg宏的第2个参数不能被指定为<strong>char</strong>、<strong>short</strong>或者<strong>float</strong>类型。<br>因为char和short类型的参数会被转换为int类型，而float类型的参数会被转换为double类型 &#8230;&#8230;<br>例如，这样写<strong>肯定是不对</strong>的：<br>c = va_arg(ap,char);<br>因为我们无法传递一个char类型参数，如果传递了，它将会被自动转化为int类型。上面的式子应该写成：<br>c = va_arg(ap,int);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——《C陷阱与缺陷》p164<br><br>
<hr width="90%">
<br>2009/05/07 修改：<br>printf函数族有用于short的控制符&#8220;h&#8221;。<br>见：<a href="http://www.cplusplus.com/reference/clibrary/cstdio/printf/"><u><font color=#0000ff>http://www.cplusplus.com/reference/clibrary/cstdio/printf/</font></u></a><br><br>
<hr width="90%">
<br>相关链接：<br><br>——《可变长参数列表误区与陷阱——va_end是必须的吗？》<br><a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/21/is_va_end_necessary.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/21/is_va_end_necessary.html</a><br><br>
<hr width="90%">
<br><br><a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="Creative Commons License" src="http://i.creativecommons.org/l/by-nc-sa/2.5/cn/88x31.png"></a><br><br>本<span rel="dc:type" href="http://purl.org/dc/dcmitype/Text" xmlns:dc="http://purl.org/dc/elements/1.1/">作品</span>采用<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license>知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议</a>进行许可。 <br>
<p>转载请注明 ：<br>文章作者 - OwnWaterloo<br>发表时间 - 2009年04月21日<br>原文链接 - <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/21/unacceptable_type_in_va_arg.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/21/unacceptable_type_in_va_arg.html</a></p>
<img src ="http://www.cppblog.com/ownwaterloo/aggbug/80655.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ownwaterloo/" target="_blank">OwnWaterloo</a> 2009-04-21 23:41 <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/21/unacceptable_type_in_va_arg.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>可变长参数列表误区与陷阱——va_end是必须的吗？</title><link>http://www.cppblog.com/ownwaterloo/archive/2009/04/21/is_va_end_necessary.html</link><dc:creator>OwnWaterloo</dc:creator><author>OwnWaterloo</author><pubDate>Tue, 21 Apr 2009 07:53:00 GMT</pubDate><guid>http://www.cppblog.com/ownwaterloo/archive/2009/04/21/is_va_end_necessary.html</guid><wfw:comment>http://www.cppblog.com/ownwaterloo/comments/80616.html</wfw:comment><comments>http://www.cppblog.com/ownwaterloo/archive/2009/04/21/is_va_end_necessary.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/ownwaterloo/comments/commentRss/80616.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ownwaterloo/services/trackbacks/80616.html</trackback:ping><description><![CDATA[<p>这本应是一个无须争论的问题——当然必须调用。<br><br>stdarg（或varargs，下略）中提供的功能就是一种<strong style="COLOR: red">契约</strong>：<br>&#8220;你按我的约定方式使用这些宏<br>——即<strong><span style="COLOR: red">必须</span>调用</strong>va_end<br>——我就给你提供实现可变长参数列表所需要的功能。&#8221;<br><br><br>使用stdarg本来是<strong>很<span style="COLOR: red">简单</span></strong>的事情<br>——<strong>按照</strong>一个简单的<strong>契约</strong>（另见相关链接）<strong>办事</strong>就可以了<br>——根本无须了解其具体实现。<br><br>有人乐意去研究该功能是如何实现的， 也很好。<br><br><br>可是某些人<br>——或通过研究其的实现，或通过实践<br>——发现他所使用的平台下， va_end是可以忽略的。<br>之后，他就开始大放厥词 ： &#8220;va_end是不必要的！&#8221;<br><br>由此， 造成一些不必要的误解与争论。<br><br>
<hr width="80%">
<br>让我们看看对va_end的两种态度：<br><br>
<hr width="80%">
<br>一、 va_end能省则省？<br><br>假设你使用的某个C/C++编译器，提供的va_end是可忽略的。<br>比如msvc中的va_end的实现如下：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;<span style="COLOR: #ff00ff">va_end</span>(<span style="COLOR: #808080">ap</span>)&nbsp;<span style="COLOR: #808080">ap</span>&nbsp;=&nbsp;(<span style="COLOR: #0000ff">va_list</span>)0&nbsp;&nbsp;<span style="COLOR: #008000">/*&nbsp;将ap<strong>置空</strong>&nbsp;*/</span></span></div>
<br>
<p>通常直接使用va_start的函数（假设叫<strong>f</strong>）的实现体会<strong>很短</strong>。：<br>1.&nbsp;用<span style="COLOR: #ff00ff">va_start</span>初始化<span style="COLOR: #0000ff">va_list</span><br>2. 调用一个使用<strong>va_list</strong>参数的函数（假设叫<strong>vf</strong>）<br>（vf 是一个固定参数列表的函数）。<br><br>因为f的实现体非常短， 一眼望穿。<br>所以你能确保vf返回后， ap不会再被你使用。<br><br>因此， 将ap置空除了浪费CPU周期， 没有实际意义， 是这样吗？<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一、1.&nbsp; 编译器参与优化<br><br>你能发现代码末尾ap不再被使用， va_end将其置空毫无意义。<br>那么，你的编译器能发现这个问题么？<br><br>请查证一下。<br>如果编译器也知道， 并且没有为va_end生成任何代码， 那么省略va_end就是不必要的了。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一、2. 编译器不参与优化<br><br>你编译器真为va_end生成了无意义并且令人感到无法接受的机器码时，该怎么办？<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一、2.1 你只在该编译器下工作<br><br>那么，你省略va_end好了。<br>但请不要宣扬一些带有<strong><span style="COLOR: #ff0000">误导</span>性质</strong>的言辞。<br>当你说&#8220;va_end是不需要&#8221;的时候， 请附带说明：<br>1. 你的平台<br>2. 你<strong><span style="COLOR: #ff0000">不</span>考虑跨平台</strong><br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一、2.2 需要要考虑移植到其他编译器<br><br><strong>注意</strong>， 其他编译器包括（但不限于）：<br>——不同<strong>架构</strong>上的编译器<br>——相同架构上的不同<strong>编译器产品</strong><br>——相同架构上的相同编译器产品的<strong>不同版本</strong>。<br><br>需要分析在该编译器下，对va_end的处理是否<strong>依然可以被省略</strong>。<br>——显然，这是一项<strong>乏味</strong>的工作。<br><br><br>即使你在源代码中写入 ：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;va_end&nbsp;is&nbsp;trivial,&nbsp;omit&nbsp;it&nbsp;</span><span style="COLOR: #008000">*/</span></div>
<p>也难保它<strong>不会被<span style="COLOR: #ff0000">遗忘</span></strong><br>—— 移植一个程序的时候有<strong>太多工作</strong>要做。<br>这么一个不起眼的地方， 会被想起来么？<br><br><br>如果在被移植的编译器上：<br>1. 省略va_end将导致函数不能正常返回（见附录）<br>也许立马就能发现这个bug。<br>崩掉了嘛， 当然要引起&#8220;重视&#8221;。<br><br>2. 省略va_end不会立马崩溃， 而是导致内存泄露（见附录）<br>情况就很<strong style="COLOR: #ff0000">严重</strong>了。<br>程序依然运行&#8220;良好&#8221;。<br>但是调用一次函数， 就泄漏一点点内存。<br><br>这恐怕就要花很多时间才能查出来了。<br>如果项目时间再紧一点， 也许根本就来不及修复这个bug就发布了。<br>反正漏得也&#8220;不多&#8221;， 你说是吧？<br><br></p>
<p>
<hr width="80%">
<p><br>二、 va_end<strong style="COLOR: #ff0000">能留则留</strong><br><br>我们何不换个方式？ <br><br>1.&nbsp; 坚持使用va_end<br>——即便我们心里清楚它没做什么有用的事情也是如此。<br><br>代码移植本质就是： 不对平台（CPU、OS、Compiler等等）产生<span style="COLOR: #ff0000"><strong>依赖</strong></span>。<br>stdarg就是标准库提供的一种实现可变长参数列表的<strong style="COLOR: #ff0000">可移植</strong>方式。<br>我们没理由弃之不用。<br><br>如果我们在源代码中坚持使用va_end：<br>——至少在这点上，就不会<strong>对编译器产生依赖</strong>（而<strong>省略va_end</strong>，就是一种<span style="COLOR: #ff0000"><strong>依赖</strong></span>）。<br>——移植的时候， 自然无须为其操心。<br><br>2. va_end令编译器产生了<strong>令人<span style="COLOR: #ff0000">无法接受</span></strong>的<strong style="COLOR: #ff0000">无用</strong>代码时<br>——通常，这是不会发生的。 编译器厂商会考虑这个事情。<br><br>比如上面的va_end宏， 会产生一次不必要的赋值操作， 但通常会被编译器优化为空。<br>即使没有被优化为空， 一次赋值操作， 真的就是<strong>不可<span style="COLOR: #ff0000">容忍</span></strong>的么？<br><br>如果确实不能容忍， 作为一种<strong><span style="COLOR: #ff0000">特殊</span>情形</strong>， 可以这样 ：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">#if</span><span style="COLOR: #000000">&nbsp;<span style="COLOR: #0000ff">defined</span>(<span style="COLOR: #ff00ff">COMPILER1</span>)&nbsp;||&nbsp;<span style="COLOR: #0000ff">defined</span>(<span style="COLOR: #ff00ff">COMPILER2</span>)&nbsp;<strong>||&nbsp;...</strong></span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">*&nbsp;<strong style="COLOR: #ff0000">special</strong>&nbsp;situation<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;machine&nbsp;code&nbsp;generated&nbsp;by&nbsp;these&nbsp;compliers&nbsp;is&nbsp;<strong style="COLOR: #ff0000">unacceptable</strong>,&nbsp;omit&nbsp;it<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">#else</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;<span style="COLOR: #ff0000"><strong>general</strong></span>&nbsp;situation&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #ff00ff">va_end</span>(<span style="COLOR: #666699"><strong>ap</strong></span>);<br></span><span style="COLOR: #0000ff">#endif</span></div>
<p><br>
<hr width="80%">
<br>附录 —— 看看大牛们是怎么说的。<br><br>从一个使用过va_start()的函数中退出之前，<strong>必须</strong>调用一次va_end()。<br>这是因为va_start<strong>可能</strong>以某种方式<strong>修改了堆栈</strong>，这种修改可能导致<strong>返回<span style="COLOR: #ff0000">无法完成</span></strong>，va_end()能将有关的修改复原。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——《C++程序设计语言》 第3版、特别版， p139<br>——即上面提到的 &#8220;立即崩溃&#8221;。<br><br><br>我们务必记住，在使用完va_list变量后一定要调用宏va_end。<br>在<strong>大多数</strong>C实现上，调用va_end与<strong>否并无区别</strong>。<br>但是，<strong>某些版本</strong>的va_start宏为了方便对va_list的遍历，就给参数列表<strong>动态分配内存</strong>。<br>这样一种C实现很可能利用va_end宏来释放此前动态分配的内存；<br>如果忘记调用宏va_end，最后得到的程序可能在某些机型上没有问题，而在另一些机型上则发生&#8220;<strong>内存泄露</strong>&#8221;。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——《C陷阱与缺陷》， p161<br>——即上面提到的&#8220;内存泄露&#8221;。<br><br><br><br>&#8230;&#8230; 最后，<strong>必须</strong>在函数返回之前<strong>调用</strong>va_end，以完成一些必要的<strong>清理</strong>工作。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——《C程序设计语言》 第2版， p137<br><br>&#8230;&#8230;在所有参数处理完毕后， 且在<strong>退出函数f之前</strong>，<strong>必须调用宏va_end一次</strong> &#8230;&#8230;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——《C程序设计语言》 第2版， p232
<p>&nbsp;</p>
<p>
<hr width="90%">
<br>相关链接：
<p><br>——可变长参数列表误区与陷阱——va_arg不可接受的类型<br><a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/21/unacceptable_type_in_va_arg.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/21/unacceptable_type_in_va_arg.html</a><br>这是使用stdarg提供的功能需要遵守契约之一。<br>契约本身仍然是简单的。<br>契约背后的原理也许比较晦涩， 但也可以不必关心。<br></p>
<hr width="90%">
<br><a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="Creative Commons License" src="http://i.creativecommons.org/l/by-nc-sa/2.5/cn/88x31.png"></a><br>本<span xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://purl.org/dc/dcmitype/Text" rel="dc:type">作品</span>采用<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license>知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议</a>进行许可。 <br><br>转载请注明 ：<br>文章作者 - OwnWaterloo<br>发表时间 - 2009年04月21日<br>原文链接 - <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/21/is_va_end_necessary.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/21/is_va_end_necessary.html</a> 
<img src ="http://www.cppblog.com/ownwaterloo/aggbug/80616.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ownwaterloo/" target="_blank">OwnWaterloo</a> 2009-04-21 15:53 <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/21/is_va_end_necessary.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编译器选项——语言</title><link>http://www.cppblog.com/ownwaterloo/archive/2009/04/20/compiler_options_language.html</link><dc:creator>OwnWaterloo</dc:creator><author>OwnWaterloo</author><pubDate>Mon, 20 Apr 2009 07:02:00 GMT</pubDate><guid>http://www.cppblog.com/ownwaterloo/archive/2009/04/20/compiler_options_language.html</guid><wfw:comment>http://www.cppblog.com/ownwaterloo/comments/80538.html</wfw:comment><comments>http://www.cppblog.com/ownwaterloo/archive/2009/04/20/compiler_options_language.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ownwaterloo/comments/commentRss/80538.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ownwaterloo/services/trackbacks/80538.html</trackback:ping><description><![CDATA[<p>一、 统一的预处理、编译、链接程序<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一、1. 有些程序同时具有如下功能：<br><br>1. 预处理C/C++源代码<br>2. 编译C/C++源代码<br>3. 链接C/C++目标代码<br><br>例如：GCC的gcc、g++，MSVC的cl.exe。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一、2. 实际的情况也许更加复杂：<br><br>gcc、g++、cl.exe很有可能只是一个<strong>启动器</strong>。<br>用户只需要使用它们， 它们内部再根据<strong><span style="COLOR: red">特定</span>条件</strong>， 执行其他程序，比如：<br><br>1.&nbsp;gcc、g++编译C/C++代码时， 最终会执行<strong>cc1</strong>/<strong>cc1plus</strong>程序。<br>该程序可能才是真正的C/C++编译器。<br><br>2. gcc、g++在链接C/C++目标代码时，最终会执行<strong>ld</strong>程序。<br>该程序可能才是真正的链接器。<br><br>3. cl.exe程序自己处理C/C++代码的预处理与编译工作。<br><br>4. cl.exe程序链接时，将执行<strong>link.exe</strong>。<br>该程序可能才是真正的链接器。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一、3. 我们的关注点<br><br>——上述复杂的情况我们大多数情况下无须操心：<br><br>1. 我们只需要使用gcc、g++<br>即使以后GCC将cc1、cc1plus、ld改为别的名字也不会受影响。<br><br>2. 我们只需要使用cl<br>即使以后cl不再担任编译工作或者link.exe被改为别的名字，同样不受影响。<br><br><br>——我们需要关心这些统一的程序，是<strong>根据何种条件</strong>， 决定它们的操作的？<br><br>本文只讨论编译：<br>1. 它们<strong>默认</strong>是通过何种条件， 决定<strong>按C语法或按C++语法</strong>编译一个翻译单元的。<br>2. 如何<strong>显式指定</strong>按C语法或者按C++语法去编译一个翻译单元。<br><br>
<hr width="80%">
<br>二、 默认情况<br><br>如果不显式指定操作， gcc、g++、cl都是按文件后缀名来决定操作的。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二、1. 测试文件：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#ifndef&nbsp;__cplusplus<br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;being&nbsp;treated&nbsp;as&nbsp;C&nbsp;translation&nbsp;unit&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">#error</span><span style="COLOR: #000000">&nbsp;!---&nbsp;&nbsp;C&nbsp;&nbsp;---!</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">#else</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;being&nbsp;treated&nbsp;as&nbsp;C++&nbsp;translation&nbsp;unit</span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">#error</span><span style="COLOR: #000000">&nbsp;!---&nbsp;C++&nbsp;---!</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000"><br></span></div>
<p>我们建一个没有后缀的文件，叫nosuffix， 写入如上内容。<br>而且， 我们也不需要编译出目标代码。<br>只需要测试__cplusplus宏（见《<a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html"><strong>预定义__cplusplus宏</strong></a>》）是否存在，并且用#error报告即可。<br><br>然后建立一些内容完全一样的文件：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">nosuffix</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br></span></div>
<p><br>这些文件共有10个：<br>c.c、 cpp.cpp、txt.txt、UC.C、UCPP.CPP、cc.cc、cxx.cxx、inl.inl、c++.c++、cp.cp。<br>（UC和UCPP是为了测试大写后缀名）<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二、2. 测试方法<br><br>对GCC使用：<br>gcc(g++) filename &gt;stdout.txt 2&gt;stderr.txt<br><br>对MSVC使用：<br>cl filename &gt;stdout.txt 2&gt;stderr.txt<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二、3. 测试结果<br><br>gcc、g++、cl对以下后缀名文件的默认操作如下<a id=suffix_test>表</a>：<br>
<table style="WIDTH: 541px; BORDER-COLLAPSE: collapse; HEIGHT: 135px" cellSpacing=0 cellPadding=3 border=1>
    <tbody>
        <tr>
            <td>
            <p align=center>&nbsp;</p>
            </td>
            <td>
            <p align=center>nosuffix</p>
            </td>
            <td>
            <p align=center>.c</p>
            </td>
            <td>
            <p align=center>.cpp</p>
            </td>
            <td>
            <p align=center>.txt</p>
            </td>
            <td>
            <p align=center>.C</p>
            </td>
            <td>
            <p align=center>.CPP</p>
            </td>
            <td>
            <p align=center>.cc</p>
            </td>
            <td>
            <p align=center>.cxx</p>
            </td>
            <td>
            <p align=center>.inl</p>
            </td>
            <td>
            <p align=center>.c++</p>
            </td>
            <td>
            <p align=center>.cp</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=center>gcc</p>
            </td>
            <td>
            <p align=center>obj</p>
            </td>
            <td>
            <p align=center>C </p>
            </td>
            <td>
            <p align=center>C++ </p>
            </td>
            <td>
            <p align=center>obj</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>obj</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=center>g++</p>
            </td>
            <td>
            <p align=center>obj</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>C++ </p>
            </td>
            <td>
            <p align=center>obj</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>obj</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=center>cl</p>
            </td>
            <td>
            <p align=center>obj</p>
            </td>
            <td>
            <p align=center>C</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>obj</p>
            </td>
            <td>
            <p align=center>C</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>C++</p>
            </td>
            <td>
            <p align=center>obj</p>
            </td>
            <td style="WIDTH: 54px; HEIGHT: 42px">
            <p align=center>obj</p>
            </td>
            <td>
            <p align=center>obj</p>
            </td>
        </tr>
    </tbody>
</table>
<br>对该表的几点说明：<br>1. 表中的obj表示该条件下， 统一程序将它们认作目标文件， 并打算执行链接工作。<br>这显然是错误的， 因为他们包含的是文本。<br><br>2. gcc、g++（编译代码）的区别<br>GCC认为带有.c、.cpp、.C、.CPP、.cc、.cxx、.c++、.cp（但不限于）后缀的文件是C/C++源文件。<br>gcc把带有.c后缀的文件， 当作C源文件， 把带有其他后缀名的文件当作C++源文件。<br>g++将带有上述所有后缀的文件，都当作C++源文件。<br><br>3. MSVC与GCC的区别<br>MSVC认为带有.c、.cpp、.C、.CPP、.cc、.cxx后缀的文件是C/C++源文件。<br>上述GCC相比， 排除了.c++和.cp<br><br>同时，windows下的文件名是不区分大小写的， 所以.c同.C，.cpp同.CPP是一样的。<br>与GCC相比， .C不再认为是C++源文件， 而是与.c一样作为C源文件处理。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二、4. 测试小结<br><br>由上表以及说明， 如果我们打算<strong>编写跨平台的代码</strong>：<br><br>1. 不推荐使用的后缀名<br>.c++、.cp<br>——因为它们不被MSVC支持<br>.C<br>——因为MSVC并不区别对待.c与.C<br><br><br>2. 可以使用的后缀名<br>——对C源文件<br>可以使用.c。<br><br>——对C++源文件<br>可以使用.cpp、.cc、.cxx。<br><br>——.CPP不推荐<br>因为在xnix上 a.CPP与a.cpp是2个文件， 而复制到Windows上就将发生重名。<br>如果只使用.cpp就可以避免该情况。<br><br><br>3. 关于.inl<br>有些文件内容确实是C/C++代码， 但是却不直接作为翻译单元，而是被其他翻译单元包含。<br>理论上说，它们取任何名字都没关系。但是将它们取为.inl会得到一些好处：<br>&nbsp;&nbsp;&nbsp; ——&nbsp; 暗示该文件包含C/C++代码<br>&nbsp;&nbsp;&nbsp; ——&nbsp; 一些编辑器会对其按C/C++语法进行高亮。<br><br>
<hr width="80%">
<br><br>三、 显式指定<br><br>有时候需要覆盖默认情况，显式指定我们需要的操作。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 三、1. GCC &#8220;<strong>-x</strong>&#8221;<br><br>GCC通过-x选项显式指定编译源代码的语言：<br>-x c（或-xc）<br>&nbsp;&nbsp;&nbsp; ——&nbsp; 将源代码作为C源文件。<br>-x c++、（或-xc++）<br>&nbsp;&nbsp;&nbsp; ——&nbsp; 将源代码作为C++源文件。<br><br>对于&#8220;二&#8221;中的测试， 只要将命令行改为：<br>gcc(g++) -x c (-xc) filename<br><br>所有文件都将被作为C源文件处理， 并输出 error !--- &nbsp;C&nbsp; ---!<br><br>而使用如下命令行：<br>gcc(g++) -x c++ (-xc++) filename<br><br>所有文件都将被作为C++源文件处理， 并输出 error !--- C++ ---!<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 三、2. MSVC &#8220;/TC&#8221; &#8220;/TP&#8221;<br><br>MSVC通过/TC（/TP）选项， 显式指定将输入作为C（C++）源代码。<br><br>对&#8220;二&#8221;中的测试， 命令行：<br>cl /TC filename<br><br>对所有文件都将输出 error !--- &nbsp;C&nbsp; --- !<br>
<p>&nbsp;</p>
<p>命令行：<br>cl /TP filename<br><br>对所有文件都将输出 error !--- C++ ---!<br><br><br><br>
<hr width="80%">
<br><br>四、总结<br><br>1. 使用&#8220;二、4&#8221;中推荐的方式，给源代码文件命名。<br>2. 覆盖默认情况，使用-x(GCC)或者/TC、/TP（MSVC）<br>3. 顺带提一点， gcc、g++用作链接时， 也有一些区别。<br>链接C++（或者C/C++混合）目标代码， 推荐使用g++。<br>因为GCC高版本中， gcc链接时默认不会导入C++需要的运行时库。<br><br><br>
<hr width="90%">
<br><br>相关链接：<br><br>——源代码<br><a href="http://immature.googlecode.com/svn/trunk/iMmature/sample/compiler_options/language">http://immature.googlecode.com/svn/trunk/iMmature/sample/compiler_options/language<br></a><br>——《<a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html">预定义__cplusplus宏</a>》<br><a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html</a><br><br><br>
<hr width="90%">
<p><br><a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="Creative Commons License" src="http://i.creativecommons.org/l/by-nc-sa/2.5/cn/88x31.png"></a><br>本<span xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://purl.org/dc/dcmitype/Text" rel="dc:type">作品</span>采用<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license>知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议</a>进行许可。 <br><br>转载请注明 ：<br>文章作者 - OwnWaterloo<br>发表时间 - 2009年04月20日<br>原文链接 - <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/20/compiler_options_language.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/20/compiler_options_language.html</a></p>
<img src ="http://www.cppblog.com/ownwaterloo/aggbug/80538.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ownwaterloo/" target="_blank">OwnWaterloo</a> 2009-04-20 15:02 <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/20/compiler_options_language.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>预定义__cplusplus宏</title><link>http://www.cppblog.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html</link><dc:creator>OwnWaterloo</dc:creator><author>OwnWaterloo</author><pubDate>Mon, 20 Apr 2009 06:42:00 GMT</pubDate><guid>http://www.cppblog.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html</guid><wfw:comment>http://www.cppblog.com/ownwaterloo/comments/80537.html</wfw:comment><comments>http://www.cppblog.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ownwaterloo/comments/commentRss/80537.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ownwaterloo/services/trackbacks/80537.html</trackback:ping><description><![CDATA[<p>一、 介绍预定义宏"__cplusplus"<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一.1 __cplusplus宏在C++标准中的描述如下：<br><br>16.8 Predefined macro names<br>__cplusplus The name __cplusplus is defined to the value <strong style="COLOR: red">199711L</strong> when compiling a C++ translation unit.143)<br>143) It is <strong>intended</strong> that future versions of this standard will replace the value of this macro with a greater value.<br>Non-conforming compilers should use a value with <strong>at most five decimal digits</strong>.<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;—— ISO C++03 p315<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;—— ISO C++98 p309<br><br>如果一段代码是需要针对C++编写的， 可以使用该宏进行条件编译。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一.2 __cplusplus的值是<strong>为了</strong>表示C++的版本<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一.3 __cplusplus的类型是"long int"<br><br><br>——这是理论上的。<br>现在发布的C++标准只有C++98， C++03是C++98的<strong>修订</strong>， 内容只有很少改变。<br>所以在ISO C++03中， 也规定该宏的值是199711L（这是一个<strong>长整数字面值</strong>）。<br><br>——实际上， 目前<strong>不应该<span style="COLOR: red">依赖</span>该</strong>宏的值， 因为：<br>1. 目前标准中规定的值只有一个——199711L， 没有根据该值进行条件编译的可能。<br><br>2. 目前C++编译器并不一定<strong>按标准实现</strong>这个宏（见测试）。<br><br>
<hr width="80%">
<br>二、 测试预定义宏__cplusplus<br><br>示例1：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()&nbsp;{<br><br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;TO_LITERAL(text)&nbsp;TO_LITERAL_(text)</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;TO_LITERAL_(text)&nbsp;#text</span><span style="COLOR: #000000"><br>#ifndef&nbsp;__cplusplus<br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;this&nbsp;translation&nbsp;unit&nbsp;is&nbsp;being&nbsp;treated&nbsp;as&nbsp;a&nbsp;C&nbsp;one&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">a&nbsp;C&nbsp;program\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #0000ff">#else</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;this&nbsp;translation&nbsp;unit&nbsp;is&nbsp;being&nbsp;treated&nbsp;as&nbsp;a&nbsp;C++&nbsp;one</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">a&nbsp;C++&nbsp;program\n__cplusplus&nbsp;expands&nbsp;to&nbsp;\</span><span style="COLOR: #000000">""<br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TO_LITERAL(__cplusplus)&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)getchar();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br></span></div>
<p>代码很简单：<br>如果没有定义__cplusplus， 那么当前源代码被当作C源代码处理。<br>如果定义了__cplusplus，那么当前源代码被当中C++源代码处理， 并且输出__cplusplus宏被展开后的字符串。<br><br><br>示例2：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">__cplusplus</span></div>
<p>这段代码更简单了， 只是使用了__cplusplus宏。<br>然后查看预处理（见《<a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/get_result_of_preprocessing.html"><strong>查看源文件预处理结果</strong></a>》），看其被扩展后的结果。<br><br>
<hr width="80%">
<br>三、 测试结果<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——msvc8<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——msvc9<br>__cplusplus按照标准被扩展为——199711L。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——msvc6<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——gcc (GCC) 3.4.2 (mingw-special)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ——gcc (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu3)<br>__cplusplus只是简单的被扩展为——1。<br><br><br>这也说明了不应该依赖__cplusplus宏的值。<br><br>
<hr width="90%">
<br>相关链接：<br><br>——源代码<br><a href="http://immature.googlecode.com/svn/trunk/iMmature/sample/predefined_macro/__cplusplus">http://immature.googlecode.com/svn/trunk/iMmature/sample/predefined_macro/__cplusplus</a><br><br>——《<a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/get_result_of_preprocessing.html">查看源文件预处理结果</a>》<br><a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/get_result_of_preprocessing.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/16/get_result_of_preprocessing.html</a><br><br>
<hr width="90%">
<br><a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="Creative Commons License" src="http://i.creativecommons.org/l/by-nc-sa/2.5/cn/88x31.png"></a><br>本<span xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://purl.org/dc/dcmitype/Text" rel="dc:type">作品</span>采用<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license>知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议</a>进行许可。 <br><br>转载请注明 ：<br>文章作者 - OwnWaterloo<br>发表时间 - 2009年04月20日<br>原文链接 - <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html</a> 
<img src ="http://www.cppblog.com/ownwaterloo/aggbug/80537.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ownwaterloo/" target="_blank">OwnWaterloo</a> 2009-04-20 14:42 <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/20/predefined_macro___cplusplus.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>预定义__GNUC__宏</title><link>http://www.cppblog.com/ownwaterloo/archive/2009/04/16/predefined_macro___GNUC__.html</link><dc:creator>OwnWaterloo</dc:creator><author>OwnWaterloo</author><pubDate>Thu, 16 Apr 2009 12:07:00 GMT</pubDate><guid>http://www.cppblog.com/ownwaterloo/archive/2009/04/16/predefined_macro___GNUC__.html</guid><wfw:comment>http://www.cppblog.com/ownwaterloo/comments/80178.html</wfw:comment><comments>http://www.cppblog.com/ownwaterloo/archive/2009/04/16/predefined_macro___GNUC__.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ownwaterloo/comments/commentRss/80178.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ownwaterloo/services/trackbacks/80178.html</trackback:ping><description><![CDATA[<p>一、 介绍预定义宏&#8220;__GNUC__&#8221;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一.1 __GNUC__ 是gcc编译器编译代码时预定义的一个宏。<br><br>需要针对gcc编写代码时， 可以使用该宏进行条件编译。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一.2 __GNUC__ 的值表示gcc的版本。<br><br>需要针对gcc特定版本编写代码时，也可以使用该宏进行条件编译。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一.3 __GNUC__ 的类型是&#8220;int&#8221;<br><br>该宏被扩展后， 得到的是<strong>整数字面值</strong>。<br>可以通过<strong>仅预处理</strong>，查看宏扩展后的<strong>文本</strong>。见：《<strong><a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/get_result_of_preprocessing.html#__GNUC__"><strong>查看源文件预处理结果</strong></a></strong>》<br>同时下面的示例也能体现出这一点。<br><br>
<hr width="80%">
<br>二、 测试预定义宏__GNUC__<br><br>示例：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">assert.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typeinfo</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br>#ifndef&nbsp;__GNUC__<br></span><span style="COLOR: #0000ff">#error</span><span style="COLOR: #000000">&nbsp;sample&nbsp;for&nbsp;gcc&nbsp;compiler</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">#else</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;use&nbsp;gcc&nbsp;special&nbsp;extension:&nbsp;#warning&nbsp;,&nbsp;__attribute__,&nbsp;etc.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">hello&nbsp;gcc&nbsp;%d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,__GNUC__);<br>&nbsp;&nbsp;&nbsp;&nbsp;assert(&nbsp;typeid(__GNUC__)</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">typeid(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)&nbsp;);<br>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">press&nbsp;Enter&nbsp;to&nbsp;exit\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)getchar();<br>}<br></span></div>
<p><br>
<hr width="90%">
<br>修改：<br><br>——2009/04/18<br><br>__GNUC__<br>__GNUC_MINOR__<br>__GNUC_PATCHLEVEL__<br>These macros are defined by all GNU compilers that use the C preprocessor:<br>C, C++, and Objective-C. Their values are the major version, minor version,<br>and patch level of the compiler, as <strong><span style="COLOR: red">integer</span> constants</strong>. For example, GCC 3.2.1<br>will define __GNUC__ to 3, __GNUC_MINOR__ to 2, and __GNUC_PATCHLEVEL__ to<br>1. They are defined only when the entire compiler is in use; if you invoke the<br>preprocessor directly, they are not defined.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;—— <a href="http://gcc.gnu.org/onlinedocs/gcc-3.1.1/cpp/Common-Predefined-Macros.html#Common%20Predefined%20Macros"><u><font color=#0000ff>http://gcc.gnu.org/onlinedocs/gcc-3.1.1/cpp/Common-Predefined-Macros.html#Common%20Predefined%20Macros</font></u></a><br>
<hr width="90%">
<br>相关链接：<br><br>——源代码<br><a href="http://immature.googlecode.com/svn/trunk/iMmature/sample/predefined_macro/extension/__GNUC__/">http://immature.googlecode.com/svn/trunk/iMmature/sample/predefined_macro/extension/__GNUC__/</a><br><br>——《查看源文件预处理结果》<br><a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/get_result_of_preprocessing.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/16/get_result_of_preprocessing.html</a><br><br>——《预定义_MSC_VER宏》<br><a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/15/predefined_macro__MSC_VER.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/15/predefined_macro__MSC_VER.html</a><br><br><br>
<hr width="90%">
<br>&nbsp; <a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="Creative Commons License" src="http://i.creativecommons.org/l/by-nc-sa/2.5/cn/88x31.png"></a><br>本<span xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://purl.org/dc/dcmitype/Text" rel="dc:type">作品</span>采用<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license>知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议</a>进行许可。 <br><br>转载请注明 ：<br>文章作者 - OwnWaterloo<br>发表时间 - 2009年04月16日<br>原文链接 - <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/predefined_macro___GNUC__.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/16/predefined_macro___GNUC__.html</a> 
<img src ="http://www.cppblog.com/ownwaterloo/aggbug/80178.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ownwaterloo/" target="_blank">OwnWaterloo</a> 2009-04-16 20:07 <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/predefined_macro___GNUC__.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>配置msvc命令行环境(续)——编写msvc编译脚本</title><link>http://www.cppblog.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html</link><dc:creator>OwnWaterloo</dc:creator><author>OwnWaterloo</author><pubDate>Wed, 15 Apr 2009 19:42:00 GMT</pubDate><guid>http://www.cppblog.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html</guid><wfw:comment>http://www.cppblog.com/ownwaterloo/comments/80101.html</wfw:comment><comments>http://www.cppblog.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ownwaterloo/comments/commentRss/80101.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ownwaterloo/services/trackbacks/80101.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 为多个VC版本编写编译脚本&nbsp;&nbsp;<a href='http://www.cppblog.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html'>阅读全文</a><img src ="http://www.cppblog.com/ownwaterloo/aggbug/80101.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ownwaterloo/" target="_blank">OwnWaterloo</a> 2009-04-16 03:42 <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>查看源文件预处理结果</title><link>http://www.cppblog.com/ownwaterloo/archive/2009/04/16/get_result_of_preprocessing.html</link><dc:creator>OwnWaterloo</dc:creator><author>OwnWaterloo</author><pubDate>Wed, 15 Apr 2009 16:49:00 GMT</pubDate><guid>http://www.cppblog.com/ownwaterloo/archive/2009/04/16/get_result_of_preprocessing.html</guid><wfw:comment>http://www.cppblog.com/ownwaterloo/comments/80093.html</wfw:comment><comments>http://www.cppblog.com/ownwaterloo/archive/2009/04/16/get_result_of_preprocessing.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/ownwaterloo/comments/commentRss/80093.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ownwaterloo/services/trackbacks/80093.html</trackback:ping><description><![CDATA[<p>编译C/C++源代码时，源代码首先会被预处理器（preprocessor）进行预处理（preprocess）。<br>预处理器执行源代码中的<strong>预处理指令</strong>，如：<br>——文件包含<br>#include<br>——条件编译<br>#if、 #ifdef、 #ifndef、 #elif、 #else、 #endif<br>——宏<br>#define、 #undef、宏标识符、宏扩展<br>——其他<br>#error、#line、#pragma<br>&#8230;&#8230;<br><br>预处理之后的结果（即将提交给编译器）与程序员看到的源代码也许会有<strong>很大的差异</strong>。<br>尤其在源代码中含有许多错综复杂的宏与条件编译时。<br>当我们被这些<strong>狂乱</strong>的宏与条件编译折磨的时候， 如果能看到预处理的结果， 也许会有很大的帮助。<br><br>下面将以一个示例说明msvc与gcc中得到预处理结果的方式。<br><br>
<hr width="80%">
<br>零、 示例<br><br>假设我们需要查看 <a title=《预定义_MSC_VER宏》 href="http://www.cppblog.com/ownwaterloo/archive/2009/04/15/predefined_macro__MSC_VER.html"><strong>_MSC_VER</strong></a> 与&nbsp;<a title=《预定义_MSC_VER宏》 href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/predefined_macro___GNUC__.html"><strong>__GUNC__</strong></a> 两个宏最终被扩展出的文本：&nbsp;<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;result&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;<br></span><span style="COLOR: #0000ff">#if</span><span style="COLOR: #000000">&nbsp;defined(__GNUC__)</span><span style="COLOR: #000000"><br>__GNUC__<br></span><span style="COLOR: #0000ff">#elif</span><span style="COLOR: #000000">&nbsp;defined(_MSC_VER)</span><span style="COLOR: #000000"><br>_MSC_VER<br></span><span style="COLOR: #0000ff">#else</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">#error</span><span style="COLOR: #000000">&nbsp;unknown&nbsp;compiler</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000"><br>;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;result;<br>}<br></span></div>
<br>该程序很简单， main函数返回一个result，然后立即退出。<br>而result的值， 根据条件编译得到：<br>1. 如果是GCC编译器， 那么result赋值为__GNUC__<br>2. 否则如果是VC编译器， 那么result赋值为_MSC_VER<br>3. 否则是一个未知的编译器， 错误<br><br>接下来， 我们来看看_MSC_VER与__GNUC__这2个宏最终到底被扩展为什么文本。<br><br><br>
<hr width="80%">
<br>一、 GCC<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一.1、 -E 选项<br><br>-E选项将把预处理的结果，写入stdout。<br>也就是说， 执行如下命令：<br>gcc <strong>-E</strong> preporcess_only.c<br><br>就能在控制台中得到预处理后的<a id=__GNUC__>结果</a>，大致如下：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">#&nbsp;1&nbsp;"../preprocess_only.c"<br>#&nbsp;1&nbsp;"&lt;built-in&gt;"<br>#&nbsp;1&nbsp;"&lt;command&nbsp;line&gt;"<br>#&nbsp;1&nbsp;"../preprocess_only.c"<br>int&nbsp;main()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;result&nbsp;=<br><br><span style="COLOR: red"><strong>3<br></strong></span><br><br><br><br><br>;<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result;<br>}<br></div>
<p><br>可以看到， __GUNC__ 宏最终被扩展为整数字面量3（GCC 3）。<br><br>如果源代码很长，&nbsp;输出到命令行窗口中查看也许不方便。<br>如何将其输出到一个文件中呢？<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一.1.1、 重定向<br><br>因为-E是输出到stdout， 显然可以将其重定向到另一个文件， 如执行如下命令：<br>gcc -E preprocess_only.c &gt;stdout.txt<br><br>那么stdout.txt中， 就能得到刚才命令行窗口中的内容。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一.1.2、 -o （小写） 选项<br><br>-o选项用于指定出文件名。<br>对于-c， -o指定的是目标文件名。<br>对于-S ，-o指定的是汇编文件名。<br>对于-E， -o自然也可以指定预处理文件名， 如执行如下命令：<br>gcc -E preprocess_only.c <strong>-o</strong> output.txt<br><br>那么output.txt中会得到&#8220;一.1.1&#8221;中的stdout.txt和&#8220;一.1&#8221;中控制台窗口一样的结果。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一.2、-save-temps 选项</p>
<p>-save-temps选项将保留<strong>中间文件</strong>：如预处理后的结果文件、汇编代码文件与目标文件。<br>其中的预处理结果文件（通常有<strong>.i</strong>后缀）是我们所需要的。<br><br><br>举例：<br>1、 gcc -save-temps -E preprocess_only.c<br><strong>0</strong>个中间文件。<br>输出预处理结果， 同&#8220;一.1&#8221;一样， 输出到控制台窗口中。<br>对比如下命令：<br><br>1.1、&nbsp;gcc -save-temps -E preprocess_only.c -o temp_output.txt<br>1.2、 gcc -save-temps -E preprocess_only.c &gt;temp_output.txt<br>可以看出， -E选项不产生中间文件。 预处理结果就是最终结果。<br>同时可以使用 -o选项或者重定向， 把结果保存到一个文件中。<br><br><br>2、 gcc -save-temps -S preprocess_only.c<br><strong>1</strong>个中间文件： preprocess_only.i（预处理结果）<br>1个输出文件：preprocess_only.s（汇编代码）<br>对比如下命令：<br><br>2.1、 gcc -save-temps -S preprocess_only.c -o unknown<br>得到preprocess_only.i文件，内容是预处理结果，是中间文件。<br>得到unknown文件，内容是汇编代码， 是最终结果文件。<br><br><br>3、 gcc -save-temps -c preprocess_only.c<br><strong>2</strong>个中间文件： preprocess_only.i与preprocess_only.s。<br>1个输出文件： preprocess_only.o（目标代码）<br>对比如下命令：<br><br>3.1、 gcc -save-temps -c preprocess_only.c -o unknown<br>得到preprocess_only.i 与 preprocess_only.s文件，内容分别是预处理结果与汇编代码，是中间结果。<br>unknown文件， 内容是目标代码，是最终结果文件。<br><br>4、 gcc -save-temps preprocess_only.c<br><strong>3</strong>个中间文件： preprocess_only.i、preprocess_only.s、preprocess_only.o。<br>1个输出文件： a.out（a.exe&nbsp;with mingw）。<br>对比如下命令：<br><br>4.1、 gcc -save-temps preprocess_only.c -o what<br>得到上述3个文件， 是中间文件。<br>what文件（what.exe with mingw）， 内容是可执行代码， 是最终结果文件。<br><br><br>
<hr width="80%">
<br><br>二、 MSVC<br><br>VC6、8、9中与查看预处理相关的选项可以通过如下命令查看：<br>cl /help<br><br>在输出中，&nbsp;找 -PREPROCESSOR- 这个类别。<br>其中与预处理结果相关的有如下一些选项：<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二.1、/E 选项<br><br>/E preprocess to stdout<br>/E 将预处理定向到 stdout<br><br>显然， 这和&#8220;一.1&#8221;是等价的， 如：<br>cl /E preprocess_only.c<br><br>在命令行窗口中将得到类似<a id=_MSC_VER>结果</a>：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">#line&nbsp;1&nbsp;"preprocess_only.c"<br>int&nbsp;main()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;result&nbsp;=&nbsp;<br><br><br>#line&nbsp;6&nbsp;"preprocess_only.c"<br><span style="COLOR: red"><strong>1200<br></strong></span><br><br>#line&nbsp;10&nbsp;"preprocess_only.c"<br>;<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result;<br>}<br></div>
<p>可以看到， _MSC_VER宏最终被扩展为整数字面值1200（VC6）。<br><br>对于较长的源文件， 我们同样希望将结果输出到一个文件中。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二.1.1、重定向<br><br>执行：<br>cl /E preprocess_only.c &gt;stdout.txt<br><br>stdout.txt将保存上面的结果。<br><br>注意： 在msvc中，没有&#8220;一.1.2&#8221;的对应物。<br>执行：<br>cl&nbsp;/help<br><br>在输出中找到-OUTPUT FILES-类别， 可以看到没有命名预处理结果的方式。有两个相似的选项：<br>/Fe 命名可执行文件。<br>/Fp 命名预编译头文件。<br>但不是我们需要的选项。<br><br><br>也许VC认为通过 &#8220;/E + 重定向&#8221;就可以达到命名输出文件的目的。<br>所以就没有设计达到此目的的另一种方法。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;二.2、/P 选项<br><br>/P preprocess to file<br>/P 预处理到文件<br><br>执行：<br>cl /P preprocess_only.c<br><br>将得到 preprocess_only.i<br><br>/P会将对&nbsp;xxx<strong>.suffix</strong> 的预处理结果输出到 xxx<strong>.i </strong>文件中。<br><strong>没有指定文件名的方式</strong>。 如果需要<strong>指定输出文件名</strong>， 可以使用 &#8220;/E + 重定向&#8221;<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二.3 /EP 选项<br><br>/E与/P选项都将保留一部分（源文件）行信息，如&#8220;二.1&#8221;所示。<br>如果这是不需要的， 可以使用 /EP选项。<br><br>/EP preprocess to stdout, no #line<br>/EP 预处理到标准输出，没有 #line<br><br>如：<br>cl /EP preprocess_only.c<br><br>将得到如下输出：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;result&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;<br><br><br><br></span><span style="COLOR: red"><strong>1200</strong></span><span style="COLOR: #000000"><br><br><br><br>;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;result;<br>}<br></span></div>
<p><br>同样， 如果需要输出到指定文件， 可以使用<strong>重定向</strong>。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二.4 其他一些有趣的选项<br><br>1. /C （大写）<br>don't strip comments（不抽出注释）<br>如果保留注释对理解预处理结果有帮助， 可以使用这个选项。<br><br>2. /U /u<br>/u remove all predefined macros<br>/u 移除所有预定义的宏<br><br>/U&lt;name&gt; remove predefined macro<br>/U&lt;name&gt; 移除预定义的宏<br><br>比如可以通过：<br>cl /u preprocess_only.c<br>cl /U_MSC_VER preprocess_only.c<br><br>来得到一个 unknown complier错误囧&#8230;&#8230;<br><br><br>3. /D<br>/D&lt;name&gt;{=|#}&lt;text&gt; define macro<br>/D&lt;name&gt;{=|#}&lt;text&gt; 定义宏<br><br>可以通过：<br>cl /D__GUNC__=3 preprocess_only.c<br><br>来假装gcc编译器囧&#8230;&#8230;<br><br><br></p>
<p>
<hr width="90%">
<p>&nbsp;</p>
<p><br>相关链接：<br><br>——示例文件下载<br><a href="http://immature.googlecode.com/svn/trunk/iMmature/sample/compiler_options/preprocess_only/">http://immature.googlecode.com/svn/trunk/iMmature/sample/compiler_options/preprocess_only/</a><br><a href="http://www.cppblog.com/Files/ownwaterloo/preprocess_only.zip">http://www.cppblog.com/Files/ownwaterloo/preprocess_only.zip</a><br><br>——《配置msvc命令行环境》<br><a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/15/environment_for_using_cl_from_command_line.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/15/environment_for_using_cl_from_command_line.html</a><br><br>——《配置msvc命令行环境(续)——编写msvc编译脚本》<br><a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html</a><br><br>——《预定义_MSC_VER宏》<br><a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/15/predefined_macro__MSC_VER.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/15/predefined_macro__MSC_VER.html</a><br><br>——《预定义__GNUC__宏》<br><a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/predefined_macro___GNUC__.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/16/predefined_macro___GNUC__.html</a><br>&nbsp;</p>
<hr width="90%">
<p>&nbsp;</p>
<p>&nbsp;<br><a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="Creative Commons License" src="http://i.creativecommons.org/l/by-nc-sa/2.5/cn/88x31.png"></a><br>本<span xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://purl.org/dc/dcmitype/Text" rel="dc:type">作品</span>采用<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license>知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议</a>进行许可。 <br><br>转载请注明 ：<br>文章作者 - OwnWaterloo<br>发表时间 - 2009年04月16日<br>原文链接 - <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/preprocess_only.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/16/preprocess_only.html</a></p>
<img src ="http://www.cppblog.com/ownwaterloo/aggbug/80093.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ownwaterloo/" target="_blank">OwnWaterloo</a> 2009-04-16 00:49 <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/get_result_of_preprocessing.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>配置msvc命令行环境</title><link>http://www.cppblog.com/ownwaterloo/archive/2009/04/15/environment_for_using_cl_from_command_line.html</link><dc:creator>OwnWaterloo</dc:creator><author>OwnWaterloo</author><pubDate>Wed, 15 Apr 2009 13:29:00 GMT</pubDate><guid>http://www.cppblog.com/ownwaterloo/archive/2009/04/15/environment_for_using_cl_from_command_line.html</guid><wfw:comment>http://www.cppblog.com/ownwaterloo/comments/80059.html</wfw:comment><comments>http://www.cppblog.com/ownwaterloo/archive/2009/04/15/environment_for_using_cl_from_command_line.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ownwaterloo/comments/commentRss/80059.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ownwaterloo/services/trackbacks/80059.html</trackback:ping><description><![CDATA[<p>有些时候使用命令行而不是IDE去编译源代码会比较方便。<br>而在命令行下使用msvc的编译器——cl， 需要为其配置<strong>环境</strong>。<br><br>
<hr width="80%">
<br>一、 环境变量测试<br><br>测试cl的环境是否配置妥当， 可以执行如下测试：<br>win键+R 启动运行 -&gt; 输入cmd（winnt系列）或者command（win95系列） -&gt; 回车， 打开命令行窗口。<br>键入"cl"并回车， 如果有类似如下的输出 ：<br><br>--------------------------------------------------------------------------------<br>Microsoft (R) 32-bit C/C++ Optimizing Compiler Version <strong>12</strong>.00.8168 for 80x86<br>Copyright (C) Microsoft Corp 1984-1998. All rights reserved. <br><br>usage: cl [ option... ] filename... [ /link linkoption... ]<br>--------------------------------------------------------------------------------<br>Microsoft (R) 32-bit C/C++ Optimizing Compiler Version <strong>14</strong>.00.50727.42 for 80x86<br>Copyright (C) Microsoft Corporation.&nbsp; All rights reserved.<br><br>usage: cl [ option... ] filename... [ /link linkoption... ]<br>--------------------------------------------------------------------------------<br>用于 80x86 的 Microsoft (R) 32 位 C/C++ 优化编译器 <strong>15</strong>.00.30729.01 版<br>版权所有(C) Microsoft Corporation。保留所有权利。<br><br>用法: cl [ 选项... ] 文件名... [ /link 链接选项... ]
<p>--------------------------------------------------------------------------------<br><br>一般来说， 就可以在命令行下使用cl了。<br><br>cl文件版本与VS版本、VC产品版本、_MSC_VER宏的对应关系如下<a id=VS_VC_CL_MSC_VER_TABLE>表</a>：</p>
<p>
<table style="WIDTH: 480px; BORDER-COLLAPSE: collapse; HEIGHT: 126px" cellSpacing=0 cellPadding=3 border=1>
    <tbody>
        <tr>
            <td>
            <p align=center>VS版本</p>
            </td>
            <td>
            <p align=center>VC产品版本号</p>
            </td>
            <td>
            <p align=center>cl文件版本号</p>
            </td>
            <td>
            <p align=center>_MSC_VER宏的值</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=center>98</p>
            </td>
            <td>
            <p align=center>6.x</p>
            </td>
            <td>
            <p align=center>12.x</p>
            </td>
            <td>
            <p align=center>1200</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=center>2005</p>
            </td>
            <td>
            <p align=center>8.x</p>
            </td>
            <td>
            <p align=center>14.x</p>
            </td>
            <td>
            <p align=center>1400</p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=center>2008</p>
            </td>
            <td>
            <p align=center>9.x</p>
            </td>
            <td>
            <p align=center>15.x</p>
            </td>
            <td>
            <p align=center>1500</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p><br>
<hr width="80%">
<br>二、 测试失败<br><br>如果出现：<br>1. &#8220;cl不是内部或外部命令，也不是可运行的程序或批处理文件。&#8221;<br>说明cl不在Path环境变量中。<br><br>2. 找不到xxx.dll。<br>cl在Path环境变量中， Path中缺少必要的dll的路径。<br><br>3. 上述测试通过， 但是在编译时出现找不到头文件或者库。<br>说明Path环境变量中有cl和必要dll的路径， 但是仍缺少其他一些环境变量。<br><br>这些情况， 都需要进一步配置环境变量。<br><br>
<hr width="80%">
<br>三、 配置环境变量<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 三.1 、让安装包帮助注册环境变量<br><br>VC6在安装的时候，会弹出一个对话框，让你选择是否注册VC6的环境变量。如下：<br><br>For your convenince, the environment variables required to run build tools from a command prompt are saved in the VCVARS32.BAT in your BIN directory<br><br>（复选框）&nbsp;<strong>Register Environment Variables<br></strong><br>Turn on this option to register environment variables for running Visual C++ tools from the command line.<br><br>默认复选框是没有选中的。<br>如果选中， 安装完毕后就会添加必要的环境变量。<br><br><br>所以， 一个办法是重新安装VC6（反正很小，相对于VC8、9安装十分快速）。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 三.2 、<a id=vc6env>手工添加环境变量</a><br><br>以VC6举例，我们可以在&nbsp;：&#8220;我的电脑&#8221; -&gt; &#8220;属性&#8221; -&gt; &#8220;高级&#8221; -&gt; &#8220;环境变量&#8221;中添加如下变量：<br><br>%Path%="<strong><em>prefix</em></strong>\Microsoft Visual Studio\VC98\Bin";%Path%<br>cl.exe所在路径。<br><br>%include%="<strong><em>prefix</em></strong>\Microsoft Visual Studio\VC98\Include";%include%<br>%lib%="<strong><em>prefix</em></strong>\Microsoft Visual Studio\VC98\Lib";%lib%<br>C/C++以及Platform SDK<br><br>%include%="<strong><em>prefix</em></strong>\Microsoft Visual Studio\VC98\MFC\Include";%include%&nbsp;&nbsp; <br>%lib%="<strong><em>prefix</em></strong>\Microsoft Visual Studio\VC98\MFC\Lib";%include%<br>MFC<br><br>%include%="<strong><em>prefix</em></strong>\Microsoft Visual Studio\VC98\ATL\Include";%include%<br>ATL<br><br>（其中的<strong><em>prefix</em></strong>是安装目录的前缀）之后就可以在命令行中使用cl了。<br><br><br>同时， VC6、8、9都提供了一个批处理<strong>vcvars32.bat</strong>。<br>我们可以查看相应的vcvars32.bat最终做了什么工作，而手工加入需要的变量。<br>下内容摘自我机器上的v<strong style="COLOR: red">s</strong>vars32.bat（VC8、9的vcvars32.bat最终调用它们）：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Code_Closed_Image_225038 onclick="this.style.display='none'; Code_Closed_Text_225038.style.display='none'; Code_Open_Image_225038.style.display='inline'; Code_Open_Text_225038.style.display='inline';" height=16 src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" width=11 align=top><img id=Code_Open_Image_225038 style="DISPLAY: none" onclick="this.style.display='none'; Code_Open_Text_225038.style.display='none'; Code_Closed_Image_225038.style.display='inline'; Code_Closed_Text_225038.style.display='inline';" height=16 src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" width=11 align=top><span id=Code_Closed_Text_225038 style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">vc8</span><span id=Code_Open_Text_225038 style="DISPLAY: none"><br><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">@set&nbsp;PATH</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\Common7\IDE;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\VC\BIN;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\Common7\Tools;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\Common7\Tools\bin;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\VC\PlatformSDK\bin;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\SDK\v2.</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">\bin;C:\WINDOWS\Microsoft.NET\Framework\v2.</span><span style="COLOR: #000000">0.50727</span><span style="COLOR: #000000">;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\VC\VCPackages;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">PATH</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000"><br>@set&nbsp;INCLUDE</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\VC\ATLMFC\INCLUDE;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\VC\INCLUDE;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\VC\PlatformSDK\include;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\SDK\v2.</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">\include;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">INCLUDE</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000"><br>@set&nbsp;LIB</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\VC\ATLMFC\LIB;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\VC\LIB;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\VC\PlatformSDK\lib;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\SDK\v2.</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">\lib;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">LIB</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000"><br>@set&nbsp;LIBPATH</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">C:\WINDOWS\Microsoft.NET\Framework\v2.</span><span style="COLOR: #000000">0.50727</span><span style="COLOR: #000000">;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">\VC\ATLMFC\LIB</span></span></div>
<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Code_Closed_Image_225000 onclick="this.style.display='none'; Code_Closed_Text_225000.style.display='none'; Code_Open_Image_225000.style.display='inline'; Code_Open_Text_225000.style.display='inline';" height=16 src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" width=11 align=top><img id=Code_Open_Image_225000 style="DISPLAY: none" onclick="this.style.display='none'; Code_Open_Text_225000.style.display='none'; Code_Closed_Image_225000.style.display='inline'; Code_Closed_Text_225000.style.display='inline';" height=16 src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" width=11 align=top><span id=Code_Closed_Text_225000 style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">vc9</span><span id=Code_Open_Text_225000 style="DISPLAY: none"><br><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">@set&nbsp;PATH</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">9.0</span><span style="COLOR: #000000">\Common7\IDE;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">9.0</span><span style="COLOR: #000000">\VC\BIN;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">9.0</span><span style="COLOR: #000000">\Common7\Tools;C:\WINDOWS\Microsoft.NET\Framework\v3.</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">;C:\WINDOWS\Microsoft.NET\Framework\v2.</span><span style="COLOR: #000000">0.50727</span><span style="COLOR: #000000">;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">9.0</span><span style="COLOR: #000000">\VC\VCPackages;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">PATH</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000"><br>@set&nbsp;INCLUDE</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">9.0</span><span style="COLOR: #000000">\VC\ATLMFC\INCLUDE;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">9.0</span><span style="COLOR: #000000">\VC\INCLUDE;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">INCLUDE</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000"><br>@set&nbsp;LIB</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">9.0</span><span style="COLOR: #000000">\VC\ATLMFC\LIB;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">9.0</span><span style="COLOR: #000000">\VC\LIB;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">LIB</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000"><br>@set&nbsp;LIBPATH</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">C:\WINDOWS\Microsoft.NET\Framework\v3.</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">;C:\WINDOWS\Microsoft.NET\Framework\v2.</span><span style="COLOR: #000000">0.50727</span><span style="COLOR: #000000">;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">9.0</span><span style="COLOR: #000000">\VC\ATLMFC\LIB;D:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio&nbsp;</span><span style="COLOR: #000000">9.0</span><span style="COLOR: #000000">\VC\LIB;</span><span style="COLOR: #000000">%</span><span style="COLOR: #000000">LIBPATH</span><span style="COLOR: #000000">%</span></span></div>
<br>可以根据它们，给VC8、9设置环境变量。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 三.3 、使用vcvars32.bat<br><br>上面提到vcvars32.bat，它们的位置如下：<br><br>VC6&nbsp; <em><strong>prefix</strong></em>\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT<br>VC8&nbsp; <strong><em>prefix</em></strong>\Microsoft Visual Studio 8\VC\bin\vcvars32.bat<br>VC9&nbsp; <strong><em>prefix</em></strong>\Microsoft Visual Studio 9.0\VC\bin\vcvars32.bat<br><br>需要注意的是： 这些批处理文件只会在<strong>当前进程</strong>中设置（局部的）环境变量，也就是说：<br><br>1. 用cmd（或者command）打开的命令行窗口中， 运行某个vcvar32.bat一次。<br>那么当前命令行窗口中就可以正常使用cl，直到关闭。<br><br>2. 写批处理文件需要使用<strong style="COLOR: red">call</strong> <strong><em>prefix</em></strong>\vcvars32.bat，而不是直接启动vcvars32.bat。<br>前者为当前进程（cpl.bat创建的进程）添加局部于进程环境变量。<br>后者启动一个进程， 为其加入环境变量， 然后该进程立即退出——没有任何作用。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 三.4、 使用VSXXCOMNTOOLS变量（VC8、9）<br><br>对于VC8、9有另一种方式——不注册全局的（系统或当前用户）环境变量，仅为当前进程设置（局部的）环境变量。<br>因为VC8、9都可以<strong>很方便</strong>的为单个进程设置环境变量。<br><br>观察vc8和vc9的vcvars32.bat的内容（位置见上）， 发现它们都只有一行：<br>"%V<span style="COLOR: red">S</span>80COMNTOOLS%v<span style="COLOR: red">s</span>vars32.bat"<br>"%V<span style="COLOR: red">S</span>90COMNTOOLS%v<span style="COLOR: red">s</span>vars32.bat"<br><br>VS80COMNTOOLS、VS90COMNTOOLS（注意不是VC而是VS）分别是VS2005和VS2008安装后会设置的环境变量。<br>所以我们也可以在自己的批处理中，很方便的为当前进程设置需要的环境变量。如下：<br><br>call "<strong>%VS80COMNTOOLS%</strong>vsvars32.bat"<br>以下cl命令将执行VC8的cl。<br><br>call "<strong>%VS90COMNTOOLS%</strong>vsvars32.bat"<br>以下cl命令将执行VC9的cl。<br><br>
<hr width="80%">
<br>四、 总结<br><br>如果仅需要使用某个版本的VC， 并且只为自己方便而使用命令行， 可以使用上面任何一种方式。<br>简单归纳如下：<br><br>1、 使用全局环境变量——在系统或当前用户变量中加入需要的值。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1 重新安装<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.2 手工加入<br><br>2、 不使用全局环境变量<br>——在执行cl前，先使用对应的vcvars32.bat（命令行窗口中执行或者脚本中call prefix\vcvars32.bat）。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.1 将vcvars32.bat加入Path变量<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.2 使用"%V<span style="COLOR: red">S</span><strong>XX</strong>COMNTOOLS%v<strong style="COLOR: red">s</strong>vars.bat" (VC8、9） 或者 absolutePath\vcvars32.bat<br><br><br>如果需要使用多个版本的VC、 或者需要将编译脚本发布给客户使用， 就不能这么随意了。<br>具体见：《<a class=titlelink id=Editor_Results_rprSelectionList_ctl01_LinkTitle href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html"><font color=#000000><strong>配置msvc命令行环境(续)——编写msvc编译脚本</strong></font></a>》<br><br>
<p>
<hr width="80%">
<br>相关链接：<br><br>——《<a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html"><font color=#000000><strong>配置msvc命令行环境(续)——编写msvc编译脚本</strong></font></a>》<br><a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html">http://www.cppblog.com/ownwaterloo/archive/2009/04/16/write_compile_script_for_msvc.html</a>
<p><br>——《<a href="http://blog.codingnow.com/2008/09/replacement_of_ide_1.html"><strong>IDE 不是程序员的唯一选择（一）</strong></a>》<br><a href="http://blog.codingnow.com/2008/09/replacement_of_ide_1.html">http://blog.codingnow.com/2008/09/replacement_of_ide_1.html</a><br><br>
<hr width="90%">
<br>&nbsp;<br><a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license><img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" alt="Creative Commons License" src="http://i.creativecommons.org/l/by-nc-sa/2.5/cn/88x31.png"></a><br>本<span rel="dc:type" href="http://purl.org/dc/dcmitype/Text" xmlns:dc="http://purl.org/dc/elements/1.1/">作品</span>采用<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/cn/" rel=license>知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议</a>进行许可。<br><br>转载请注明 ：<br>文章作者 - OwnWaterloo<br>发表时间 - 2009年04月15日<br>原文链接 - <a id=Editor_Edit_hlEntryLink title="view: 配置msvc命令行环境" href="http://www.cppblog.com/ownwaterloo/archive/2009/04/15/environment_for_using_cl_from_command_line.html" target=_blank>http://www.cppblog.com/ownwaterloo/archive/2009/04/15/environment_for_using_cl_from_command_line.html</a> 
<img src ="http://www.cppblog.com/ownwaterloo/aggbug/80059.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ownwaterloo/" target="_blank">OwnWaterloo</a> 2009-04-15 21:29 <a href="http://www.cppblog.com/ownwaterloo/archive/2009/04/15/environment_for_using_cl_from_command_line.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>