利用pre-compiled headers技术以加速编译速度
--以Borland C++ Builder为例
(四)
本文作者:王森
台湾交通大学科技管理研究所
moli.mt88g@nctu.edu.tw
<编译器指令#pragma hdrstop之前只能放系统标头文件吗?>
请大家回头看看在这之前所有被我们用来测试的程序原始文件。拿程序代码5来说,大家会发现,Unit2.cpp并没有放在编译器指令#pragma hdrstop之前,那幺是否代表笔者默认Unit2.cpp不能放在编译器指令#pragma hdrstop之前呢? 让我们来做个Project实验组,程序代码如下:
程序代码6-1:
Unit1.cpp
#include <iostream.h>
#include <stdio.h>
#include <vcl.h>
#include "Unit2.h"
#pragma hdrstop
#pragma argsused
int main(int argc, char* argv[])
{
cout << "Hello World" ;
return 0;
}
Unit2.h
#ifndef Unit2H
#define Unit2H
void test(void) ;
#endif
Unit2.cpp
#include <iostream.h>
#include <stdio.h>
#include <vcl.h>
#include "Unit2.h"
#pragma hdrstop
void test(void)
{
printf("test") ;
}
然后我们试着编译看看。接着我们一个档案都不要删除,直接把Unit2.h与Unit2.cpp叫出来,把档案内容改成:
程序代码6-2:
Unit2.h
#ifndef Unit2H
#define Unit2H
void test(void) ;
void test1(void) ;
#endif
Unit2.cpp
#include <iostream.h>
#include <stdio.h>
#include <vcl.h>
#include "Unit2.h"
#pragma hdrstop
void test(void)
{
printf("test") ;
}
void test1(void)
{
printf("test1") ;
}
再重新使用make编译。
同理,我们也做一组完全相同的Project当作对照组,档案内容几乎完全相同,除了我们把#include "Unit2.h"放回编译器指令#pragma hdrstop之后,我们也做跟上面实验组Project相同的测试:
程序代码7-1:
Unit1.cpp
#include <iostream.h>
#include <stdio.h>
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
#pragma argsused
int main(int argc, char* argv[])
{
cout << "Hello World" ;
return 0;
}
Unit2.h
#ifndef Unit2H
#define Unit2H
void test(void) ;
#endif
Unit2.cpp
#include <iostream.h>
#include <stdio.h>
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
void test(void)
{
printf("test") ;
}
程序代码7-2:
Unit2.h
#ifndef Unit2H
#define Unit2H
void test(void) ;
void test1(void) ;
#endif
Unit2.cpp
#include <iostream.h>
#include <stdio.h>
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
void test(void)
{
printf("test") ;
}
void test1(void)
{
printf("test1") ;
}
我们把这两次测试的结果列在下表
测试结果8:
Unit2.h在#pragma hdrstop之前
Unit2.h在#pragma hdrstop之后
编译次数
编译行数
编译时间
编译次数
编译行数
编译时间
第一次(build)程序代码6-1
202245
8.29
第一次(build)程序代码7-1
202258
8.65
第二次(make)程序代码6-1
0
0.14
第二次(make)程序代码7-1
0
0.16
第三次(make)程序代码6-2
202253
9.16
第三次(make)程序代码7-2
65
1.68
这个测试结果代表了什幺涵义呢?
这个测试结果并非只有系统标头文件才能放在编译器指令#pragma hdrstop之前,程序设计师自己定义的标头档也可以。
在标头档小小的更动会造成整个程序原始文件从头到尾重新编译,也使得编译器重新产生新的cache檔(注意:编译器会覆盖具有相同预先编译标记的vcl50.#??档,而非重新产生。其实这样也无可厚非,否则Lib目录下就会有好多具有相同预先编译标记的cache文件,这样可就糟糕了!)
在程序开发初期,程序标头文件常常会被修改,可是系统标头文件却几乎没有人会去动到他们,所以在整个系统的函式接口或数据结构尚未稳定之前,尽量先不要把程序设计师自己定义的标头文件放到编译器指令#pragma hdrstop之前。因为这幺一来,非但没有加速程序的编译速度,反而因为预先编译标记没有改变,可是标头档内容却变了,而迫使编译器每次都要重新编译这些标头档并产生新的cache檔(而且还要先删掉原先具有相同预先编译标记的cache文件,使得整体编译时间更长)。这个问题在我们的测试程序里并不明显,可是读者可以想象,如果今天我们是撰写GUI程序,我们常常要修改Form上的组件和事件处理函式,每次一修改,势必动到标头档(因为增添/删除组件,或是新增事件处理函式的时候都会让该Unit对应的标头档改变),如果我们的Project里头有好多Form,那事情可就不妙了!! 所以在此笔者的建议是:在程序设计初期,请先将这些程序设计师自行定义的标头文件移到编译器指令#pragma hdrstop之后(IDE所帮我们产生的Unit就是以此为预设情况),等到整个系统之中所有类别、函式接口、数据结构都大致底定的时候,再将这些标头文件移到编译器指令#pragma hdrstop之前,这样效果就会好很多。