为什么可以引用未包含的头文件内容?

缘起
最近几天奉老大之命学习研究了一下VCFVCFBuilder。我在修改编译错误的时候发现有些头文件里面引用了其他头文件里面的类,但是在该头文件里面有没有引入任何其他头文件。编译的时候也没有提示这个错误,按照我的惯性思维,这很不可思议啊!这也让我想起了VC编译环境提供的预编译头StdAfx.h也是这个现象,当时就很纳闷,可是没仔细想。这次又碰到了,忍不住想弄个明白,问了几个大虾,没有答案。那就自己来吧。

追踪
经过分析发现,有这么几个特点(我们假定有三对.h/cpp文件名字是A,B,C。A和B都没有引入任何头文件):

  1. “没有包含任何头文件”的头文件A.h和B.h,被其他头文件C.h包含了;
  2. B中引用了A中的内容,虽然没有引入A的头文件,但是在C的头文件中引入顺序在A的后面;
  3. A和B实现文件无一例外的引入了C的头文件。

这样问题就很明朗了,这里面有一个小小的trick,用一个公共的头文件C解决了引用的问题。再来看看预处理头StdAfx.h,该头文件被要求必须在使用了“预编译技术”的CPP文件中包含,而且一般情况还必须是第一个被包含的头文件。这两种方式显然有一点小小的区别:一个是通过在公共头文件中根据以来关系按顺序引入头文件,一个是通过公共文件引入系统文件和不常改动的文件,而免除了每个头文件都要引入一堆头文件的烦恼,关键是还提高了编译速度哦!

为什么?
我个人的一个习惯是,凡事都喜欢问个为什么,此事的缘起也是因为我爱刨根问底。现在让我来回答一下到底是为什么吧。已经理解的不需要继续看了,呵呵。首先我们必须明确的几个问题是:

  1. 什么文件需要被编译?
  2. #include是如何起作用的?
  3. 编译器是如何扫描处理代码的?

我们连起来回答是,你可以指定被编译的文件,一般是c/cpp文件,#include在编译的时候会将引入的文件读入展开在#include所在位置,然后由编译器逐行扫描处理代码,一般现代编译器都是扫描两次。也就是说头文件一般不会被直接进行编译的,而是通过展开在c/cpp文件对应的#include处来起它所应有的作用的。所以说,只要在c/cpp文件中#include全部被展开的时候,声明和定义能够根据依赖关系按顺序排好,就可以编译成功。

好,这就是答案!为什么有的头文件并没有包含任何头文件就不难理解了吧?

About 王永杰

路漫漫其修远兮,吾将上下而求索
This entry was posted in C&C++, 为什么?, 技术为本. Bookmark the permalink.

One Response to 为什么可以引用未包含的头文件内容?

  1. Pingback: » 为什么预编译头(Precompiled Header)能够提高编译速度? 王永杰的Blog(博客): Keep thinking, seeking and practicing!

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>