现在的位置: 首页 > 综合 > 正文

关于VC6.0的预编译

2013年05月15日 ⁄ 综合 ⁄ 共 3770字 ⁄ 字号 评论关闭

                                                                           关于VC6.0的预编译

       前几天有个QQ上的好友问我关于MFC中的WinMain()函数哪去了的问题,我只能说是MFC系统自动连接进去的,我还给了他一个设置了断点的工程文件,其中可以执行到_tWinMain()那儿停下来验证。然后他又问我为什么要通过stdafx.h包括afxwin.h而不直接包括呢,为什么还有一个stdafx.cpp什么事也没做,只包括了下stdafx.h。我只知道这个是跟VC++的预编译有关,首先我们来看在stdafx.h及stdafx.cpp中开头的二段注释:

// stdafx.h : include file for standard system include files,
//  or project specific include files that are used frequently, but
//      are changed infrequently
//

// stdafx.cpp : source file that includes just the standard includes
// XPButtonDemo.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information

     应该就可以了解到它跟预编译有关系,也隐约说到了预编译的原因。但具体,我还是搞不明白什么是所谓的预编译,所以今天特地去找书查了下,算是找到了一个大概的答案,其实具体细节我们不知道也没什么吧我想。

下面一段摘自《Visual C++6.0技术内幕》:
理解预编译头文件
    当AppWizard生成一个工程时,它生成预编译头文件的开关设置和文件。为了有效地管理工程,你必须理解如何让系统处理预编译头文件。
    注意:VC++有两个预编译头文件“系统”:自动的和手动的。自动预编译头文件用/Yx编译程序开关激活,在一个“数据库”文件中存储编译程序输出。手工预编译头文件由/Yc和/Yu开关设置激活,并且,它对于AppWizard生成的工程是极为重要的。
    预编译头文件就是在源代码特定行上获取的编译程序“快照”。在MFC库程序中,这个快照通常紧接着如下语句来获取:
    #include "stdafx.h"
    文件stdafx.h包含了MFC库文件的#include语句。文件的内容取决于在运行AppWizard的选项,但是,,此文件始终包含这些语句:
#include<afxwin.h>
#include<afxext.h>
    如果你正在使用复合文档,StdAfx.h也包含了如下语句:
#include<afxole.h>
    如果你正在使用Automation或者ActiveX控件,则它包含:
#include<afxdisp.h>
    如果你正在使用IE的公用控件,则StdAfx.h包含:
#include<afxdtctl.h>
    有时,你会需要其他头文件-例如,对于基于模板的集合类的头文件:
#include<afxtempl.h>
    源文件StdAfx.cpp中只包含如下语句:
#include"StdAfx.h"
    并且,它在工程目录中生成预编译头文件。StdAfx.h包含MFC库头文件从不改变,但是它的编译却要花费很长的时间。编译开关/Yc只与StdAfx.cpp一起使用,它将导致生成预编译头文件(.PCH)。如果与所有其它源代码文件一起使用开关/Yu,将会引起使用现有的PCH文件。开关/Fp规定PCH文件名,否则使用默认文件名,即在目标的输u出文件子目录中使用工程名(以PCH为扩展名)。
     AppWizard设置/Yc和/Yu开关,如果需要的话,也可以进行更改。你可以为单个源文件定义编译程序开关的设置。在Project Settings对话框的C/C++选项卡中,如果只选定StdAfx.cpp,将看到/Yc设置。这将覆盖为编译目标定义的/Yu设置。
     要知道,PCH文件通常很大,通常有5MB.如果不小心的话,硬盘很快就会满的。你可以定期清除工程的Debug目录,或者使用/Fp编译程序选项,来把PCH重定向到一个公用的目录中。

上面这一段讲得不明不白,我还是不知道为什么要预编译,下面这一部分摘自《Visual C++6.0程序设计与开发技术大全》:
1: 预编译头的概念:
     所谓的预编译头就是把一个工程中的那一部分代码,预先编译好放在一个文件里(通常是以pch为扩展名的),这个文件就称为预编译头文件。这些预先编译好的代码可以是任何的C/C++代码。甚至是inline的函数,但是必须是稳定的,在工程开发的过程中不会被经常改变。如果这些代码被修改,则需要重新编译生成预编译头文件。注意,生成预编译头文件是很耗时间的。同时得注意预编译头文件通常很大,通常有6~7MB大。注意及时清理那些没用的预编译头文件。编译器都有Time Stamp (时间戳)的功能,在编译整个工程的时候,它只会编译那些经过修改的文件,而不会去编译那些从上次编译到现在没有被修改过的文件。编译器是以文件为单位编译的,一个文件经过修改后会重新编译整个文件,当然在这个文件里包含的所有的头文件中的内容(.eg Macro,Preprocessor)都要重新处理一遍。VC的预编译头文件保存的正是这部分信息,以避免每次都要处理这些头文件。
2: 预编译头的作用
     预编译头文件提高了编译速度,有了它就没必要每次都编译那些不需要经常改变的代码。编译性能当然也提高了。
3: 预编译头的使用
     要使用预编译头,就必须指定一个头文件,这个头文件包含不会经常改变的代码和其他的头文件,然后用这个头文件来生成一个预编译头文件(.pch)。很多人都认为StdAfx这个文件是VC提供的一个“系统级别”的,编译器自带的头文件。其实不然,这个文件可以是任何名字。如果考察一个典型的由AppWizard生成的MFC Dialog Based程序的预编译头文件(因为AppWizard会指定好如何使用预编译头文件StdAfx.h,这是VC命名的)。则可以发现这个头文件里包含了以下的头文件:
include<afxwin.h>//MFC core and standard components
#include<afxext.h>//MFC extensions
#include<afxdisp.h>//MFC Automation classes
#include<afxdtctl.h>//MFC support for Internet Explorer 4 Common Controls
#include<afxcmn.h>
     这些正是使用MFC时必须包含的头文件,当然一般人不太可能在工程中修改这些头文件的,所以说它们是稳定的。
     那么如何指定它来生成预编译头文件呢?一个头文件是不能自行编译的,所以还需要一个cpp文件来生成.pch文件。这个文件默认的就是StdAfx.cpp。在这个文件里只有一句代码:
#include"stdafx.h"
原因是理所当然的,需要编译的仅是Stdafx.h而已。可以用/Yc编译开关来指定Stdafx.cpp生成一个.pch文件,通过/Fp开关来指定生成的.pch文件的名字。打开Project->Settings->C/C++选项卡。把Category指向Precompiled Header.
在Project Options(右下角)可以看到/Fp"debug/PCH.pch",这就是指定生成的.pch文件的名字,默认是<工程名>.pch。
然后在左边的树形视图里选择Stdafx.cpp。这时原来的Project Options变成了Source File Option,改变的原因是原来是一个工程,而现在是一个文件。在这里可以看到/Yc的作用就是指定这个文件来创建一个PCH文件。/Yc后面的文件名是那个包含了稳定代码的文件,一个工程里只能有一个文件可以有/Yc开关。VC就是根据这个选项把StdAfx.cpp编译成一个OBJ文件和一个PCH文件。
     这样,就设置好了预编译头文件。也就是说,可以使用预编译头功能了。以下是注意事项:
(1)如果使用了/Yu选项,就是说使用了预编译,在每个.cpp文件的开关,包含指定产生.pch文件的.h文件(默认是stadafx.h)。如果没有包含这个文件,则会返回Unexpected file end。
(2)如果不小心把.pch文件丢了,根据以上的分析,只要让编译器再产生一个.pch文件就可以了。也就是说把Stdafx.cpp(即指定/Yc的那个文件)重新编译一遍就可以了。

     当然,也可以自动使用,这样就变得简单了,只要指定/Yx就可以了。需要注意的是如果指定了/Yc/Yu,/Yx会被忽略,因为前者的优先级要高一些。

///////////////////////完//////////////////////////////////////

这下清楚多啦。呵呵

抱歉!评论已关闭.