<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>王永杰的Blog(博客) &#187; 为什么？</title>
	<atom:link href="http://wyj.zhuwo.info/category/why/feed/" rel="self" type="application/rss+xml" />
	<link>http://wyj.zhuwo.info</link>
	<description>Keep thinking, seeking and practicing!</description>
	<lastBuildDate>Thu, 26 Jan 2012 11:41:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>为什么预编译头(Precompiled Header)能够提高编译速度？</title>
		<link>http://wyj.zhuwo.info/2008/05/%e4%b8%ba%e4%bb%80%e4%b9%88%e9%a2%84%e7%bc%96%e8%af%91%e5%a4%b4precompiled-header%e8%83%bd%e5%a4%9f%e6%8f%90%e9%ab%98%e7%bc%96%e8%af%91%e9%80%9f%e5%ba%a6%ef%bc%9f/</link>
		<comments>http://wyj.zhuwo.info/2008/05/%e4%b8%ba%e4%bb%80%e4%b9%88%e9%a2%84%e7%bc%96%e8%af%91%e5%a4%b4precompiled-header%e8%83%bd%e5%a4%9f%e6%8f%90%e9%ab%98%e7%bc%96%e8%af%91%e9%80%9f%e5%ba%a6%ef%bc%9f/#comments</comments>
		<pubDate>Sat, 24 May 2008 10:19:58 +0000</pubDate>
		<dc:creator>王永杰</dc:creator>
				<category><![CDATA[C&C++]]></category>
		<category><![CDATA[为什么？]]></category>
		<category><![CDATA[技术为本]]></category>

		<guid isPermaLink="false">http://wyj.zhuwo.info/?p=54</guid>
		<description><![CDATA[上一篇博客我解释了“为什么可以引用未包含的头文件内容？”，这也让我想起了另外一个问题：“为什么预编译头(Precompiled Header)能够提高编译速度？”。既然要刨根问底，不妨再解释一下这个问题。其实呢，只要理解“编译 &#8211; 链接”这两个步骤各自的作用和一般编译器提高编译速度的方式，那这个问题是小菜一碟啊。 编译(Compile)——把每个源码文件编译成二进制文件（一般是obj）。链接(Link)——把所有的Obj文件堆积木一样组织在一起，形成了DLL、EXE等类型的目标文件。 一般来说，如果一个文件所依赖的所有项如头文件等都没有修改过，那么该文件就不需要重新编译。不管是makefile还是VC的project通过检测依赖关系，减少重新编译的代码量来提高编译速度的。 那么就不难理解为什么预编译头能够提高编译速度了。如果StdAfx.h里面的头文件在每一份实现文件里面都重新包含了一遍，那么每一次实现文件的修改都会导致该文件的重新编译，因而所包含的头文件都要展开一次用于重新编译，无疑会放慢编译速度。然而，如果将公用而不常修改的头文件置于StdAfx.h里面，那么编译器会在第一次遇到StdAfx.h的时候将它编译解释生成stdafx.obj和一个PCH文件，以后再遇到StdAfx.h的时候就会直接使用PCH文件，而不会重新编译了。对于MFC和SDK几万行的头文件来说，速度当然会有大大提高啦。]]></description>
			<content:encoded><![CDATA[<p><a href="http://wyj.zhuwo.info/2008/05/24/%e4%b8%ba%e4%bb%80%e4%b9%88%e5%8f%af%e4%bb%a5%e5%bc%95%e7%94%a8%e6%9c%aa%e5%8c%85%e5%90%ab%e7%9a%84%e5%a4%b4%e6%96%87%e4%bb%b6%e5%86%85%e5%ae%b9%ef%bc%9f/#more-53">上一篇博客</a>我解释了“<a title="为什么可以引用未包含的头文件内容？" href="http://wyj.zhuwo.info/2008/05/24/%e4%b8%ba%e4%bb%80%e4%b9%88%e5%8f%af%e4%bb%a5%e5%bc%95%e7%94%a8%e6%9c%aa%e5%8c%85%e5%90%ab%e7%9a%84%e5%a4%b4%e6%96%87%e4%bb%b6%e5%86%85%e5%ae%b9%ef%bc%9f/">为什么可以引用未包含的头文件内容？</a>”，这也让我想起了另外一个问题：“为什么预编译头(Precompiled Header)能够提高编译速度？”。既然要刨根问底，不妨再解释一下这个问题。其实呢，只要理解“编译 &#8211; 链接”这两个步骤各自的作用和一般编译器提高编译速度的方式，那这个问题是小菜一碟啊。</p>
<p><span id="more-54"></span>编译(Compile)——把每个源码文件编译成二进制文件（一般是obj）。链接(Link)——把所有的Obj文件堆积木一样组织在一起，形成了DLL、EXE等类型的目标文件。</p>
<p>一般来说，如果一个文件所依赖的所有项如头文件等都没有修改过，那么该文件就不需要重新编译。不管是makefile还是VC的project通过检测依赖关系，减少重新编译的代码量来提高编译速度的。</p>
<p>那么就不难理解为什么预编译头能够提高编译速度了。如果StdAfx.h里面的头文件在每一份实现文件里面都重新包含了一遍，那么每一次实现文件的修改都会导致该文件的重新编译，因而所包含的头文件都要展开一次用于重新编译，无疑会放慢编译速度。然而，如果将公用而不常修改的头文件置于StdAfx.h里面，那么编译器会在第一次遇到StdAfx.h的时候将它编译解释生成stdafx.obj和一个PCH文件，以后再遇到StdAfx.h的时候就会直接使用PCH文件，而不会重新编译了。对于MFC和SDK几万行的头文件来说，速度当然会有大大提高啦。</p>
]]></content:encoded>
			<wfw:commentRss>http://wyj.zhuwo.info/2008/05/%e4%b8%ba%e4%bb%80%e4%b9%88%e9%a2%84%e7%bc%96%e8%af%91%e5%a4%b4precompiled-header%e8%83%bd%e5%a4%9f%e6%8f%90%e9%ab%98%e7%bc%96%e8%af%91%e9%80%9f%e5%ba%a6%ef%bc%9f/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>为什么可以引用未包含的头文件内容？</title>
		<link>http://wyj.zhuwo.info/2008/05/%e4%b8%ba%e4%bb%80%e4%b9%88%e5%8f%af%e4%bb%a5%e5%bc%95%e7%94%a8%e6%9c%aa%e5%8c%85%e5%90%ab%e7%9a%84%e5%a4%b4%e6%96%87%e4%bb%b6%e5%86%85%e5%ae%b9%ef%bc%9f/</link>
		<comments>http://wyj.zhuwo.info/2008/05/%e4%b8%ba%e4%bb%80%e4%b9%88%e5%8f%af%e4%bb%a5%e5%bc%95%e7%94%a8%e6%9c%aa%e5%8c%85%e5%90%ab%e7%9a%84%e5%a4%b4%e6%96%87%e4%bb%b6%e5%86%85%e5%ae%b9%ef%bc%9f/#comments</comments>
		<pubDate>Sat, 24 May 2008 08:59:22 +0000</pubDate>
		<dc:creator>王永杰</dc:creator>
				<category><![CDATA[C&C++]]></category>
		<category><![CDATA[为什么？]]></category>
		<category><![CDATA[技术为本]]></category>

		<guid isPermaLink="false">http://wyj.zhuwo.info/?p=53</guid>
		<description><![CDATA[缘起 最近几天奉老大之命学习研究了一下VCF和VCFBuilder。我在修改编译错误的时候发现有些头文件里面引用了其他头文件里面的类，但是在该头文件里面有没有引入任何其他头文件。编译的时候也没有提示这个错误，按照我的惯性思维，这很不可思议啊！这也让我想起了VC编译环境提供的预编译头StdAfx.h也是这个现象，当时就很纳闷，可是没仔细想。这次又碰到了，忍不住想弄个明白，问了几个大虾，没有答案。那就自己来吧。 追踪 经过分析发现，有这么几个特点（我们假定有三对.h/cpp文件名字是A，B，C。A和B都没有引入任何头文件）： “没有包含任何头文件”的头文件A.h和B.h，被其他头文件C.h包含了； B中引用了A中的内容，虽然没有引入A的头文件，但是在C的头文件中引入顺序在A的后面； A和B实现文件无一例外的引入了C的头文件。 这样问题就很明朗了，这里面有一个小小的trick，用一个公共的头文件C解决了引用的问题。再来看看预处理头StdAfx.h，该头文件被要求必须在使用了“预编译技术”的CPP文件中包含，而且一般情况还必须是第一个被包含的头文件。这两种方式显然有一点小小的区别：一个是通过在公共头文件中根据以来关系按顺序引入头文件，一个是通过公共文件引入系统文件和不常改动的文件，而免除了每个头文件都要引入一堆头文件的烦恼，关键是还提高了编译速度哦！ 为什么？ 我个人的一个习惯是，凡事都喜欢问个为什么，此事的缘起也是因为我爱刨根问底。现在让我来回答一下到底是为什么吧。已经理解的不需要继续看了，呵呵。首先我们必须明确的几个问题是： 什么文件需要被编译？ #include是如何起作用的？ 编译器是如何扫描处理代码的？ 我们连起来回答是，你可以指定被编译的文件，一般是c/cpp文件，#include在编译的时候会将引入的文件读入展开在#include所在位置，然后由编译器逐行扫描处理代码，一般现代编译器都是扫描两次。也就是说头文件一般不会被直接进行编译的，而是通过展开在c/cpp文件对应的#include处来起它所应有的作用的。所以说，只要在c/cpp文件中#include全部被展开的时候，声明和定义能够根据依赖关系按顺序排好，就可以编译成功。 好，这就是答案！为什么有的头文件并没有包含任何头文件就不难理解了吧？]]></description>
			<content:encoded><![CDATA[<p><span style="color: #990000;"><span style="color: #990000;"><span style="font-weight: bold;">缘起</span></span></span><br />
最近几天奉老大之命学习研究了一下<a href="http://vcf-online.org" target="_blank">VCF</a>和<a href="http://vcfbuilder.org/" target="_blank">VCFBuilder</a>。我在修改编译错误的时候发现有些头文件里面引用了其他头文件里面的类，但是在该头文件里面有没有引入任何其他头文件。编译的时候也没有提示这个错误，按照我的惯性思维，这很不可思议啊！这也让我想起了VC编译环境提供的预编译头StdAfx.h也是这个现象，当时就很纳闷，可是没仔细想。这次又碰到了，忍不住想弄个明白，问了几个大虾，没有答案。那就自己来吧。</p>
<p><span id="more-53"></span><span style="color: #990000;"><span style="color: #990000;"><span style="font-weight: bold;">追踪</span></span></span><br />
经过分析发现，有这么几个特点（我们假定有三对.h/cpp文件名字是A，B，C。A和B都没有引入任何头文件）：</p>
<ol>
<li>“没有包含任何头文件”的头文件A.h和B.h，被其他头文件C.h包含了；</li>
<li>B中引用了A中的内容，虽然没有引入A的头文件，但是在C的头文件中引入顺序在A的后面；</li>
<li>A和B实现文件无一例外的引入了C的头文件。</li>
</ol>
<p>这样问题就很明朗了，这里面有一个小小的trick，用一个公共的头文件C解决了引用的问题。再来看看预处理头StdAfx.h，该头文件被要求必须在使用了“预编译技术”的CPP文件中包含，而且一般情况还必须是第一个被包含的头文件。这两种方式显然有一点小小的区别：一个是通过在公共头文件中根据以来关系按顺序引入头文件，一个是通过公共文件引入系统文件和不常改动的文件，而免除了每个头文件都要引入一堆头文件的烦恼，关键是还提高了编译速度哦！</p>
<p><span style="color: #990000;"><span style="color: #990000;"><span style="font-weight: bold;">为什么？</span></span></span><br />
我个人的一个习惯是，凡事都喜欢问个为什么，此事的缘起也是因为我爱刨根问底。现在让我来回答一下到底是为什么吧。已经理解的不需要继续看了，呵呵。首先我们必须明确的几个问题是：</p>
<ol>
<li> 什么文件需要被编译？</li>
<li>#include是如何起作用的？</li>
<li>编译器是如何扫描处理代码的？</li>
</ol>
<p>我们连起来回答是，你可以指定被编译的文件，一般是c/cpp文件，#include在编译的时候会将引入的文件读入展开在#include所在位置，然后由编译器逐行扫描处理代码，一般现代编译器都是扫描两次。也就是说头文件一般不会被直接进行编译的，而是通过展开在c/cpp文件对应的#include处来起它所应有的作用的。所以说，只要在c/cpp文件中#include全部被展开的时候，声明和定义能够根据依赖关系按顺序排好，就可以编译成功。</p>
<p>好，这就是答案！为什么有的头文件并没有包含任何头文件就不难理解了吧？</p>
]]></content:encoded>
			<wfw:commentRss>http://wyj.zhuwo.info/2008/05/%e4%b8%ba%e4%bb%80%e4%b9%88%e5%8f%af%e4%bb%a5%e5%bc%95%e7%94%a8%e6%9c%aa%e5%8c%85%e5%90%ab%e7%9a%84%e5%a4%b4%e6%96%87%e4%bb%b6%e5%86%85%e5%ae%b9%ef%bc%9f/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

