用VC新建个project,总是会有stdafx.h/cpp文件自动生成,只知道是预编译文件,但是预编译文件到到底是个什么东西,一直也没试着搞清楚。今天,搞清楚。
什么是预编译头文件
C/C++的编译器,会在预处理时把头文件include到源文件(source file)里。由于很多library都含有很大个的头文件,尤其是使用template的,不提供点什么机制的话,每次编译时都会重新编译这些头文件,非常inefficient。
Precompiled Header就是编译器为了解决这个问题提供的机制。
用户可以将一些很少改动的头文件指定为预编译头文件,这样编译器会在第一次编译时对这些头文件生成某种中间形式的文件。VC是.pch, GNU Compiler Collection(gcc) 是.gch。这些文件是可以被各个编译单元共享的,并且是可以更快的被编译器处理的。
取代头文件里的include和前置声明
//A.h
class A
{
};
//B.h
class B
{
A *a;
};
//main.cpp
#include "A.h"
#include "B.h"
void main()
{
}
上面的source,编译是不通过的。因为B.h里没有include A.h。但是include A.h的话,A.h一旦改变,B这个class也会被重新编译。在B.h里前置声明A是通常的做法。但是如果B里使用的是A的对象,而不是指针的话,就不能这么做了。
使用预编译头文件的话,可以省去前置声明。
//main.cpp
#include "stdafx.h"
void main()
{
}
//stdafx.h
#pragma once
#include "A.h"
#include "B.h"
编译option里,对main.cpp指定/Yu'stdafx.h',表示对main.cpp使用预编译头文件。
这样的话,A.h和B.h会被预编译到.pch里,main.cpp会使用这个.pch。
VC其实是这么做的,默认的,还会有一个stdafx.cpp。
//stdafx.cpp
#include "stdafx.h"
这个文件的编译option是/Yc 'stdafx.h',也就是生成预编译头文件。对这个option,VC不会忽略其include的文件的timestamp,所以,一旦A.h发生了变化,这个文件及它所include的头文件都会被重新编译,重新生成.pch。
gcc的话,没有这样的option。编译器所作的只是在编译头文件之前先去找和头文件名称相同的.gch文件而已。和其他obj文件一样,预编译头文件的更新,通过makefile做。
#include "A.h"
#include "B.h"
void main()
{
}
上面的source,编译是不通过的。因为B.h里没有include A.h。但是include A.h的话,A.h一旦改变,B这个class也会被重新编译。在B.h里前置声明A是通常的做法。但是如果B里使用的是A的对象,而不是指针的话,就不能这么做了。
使用预编译头文件的话,可以省去前置声明。
//main.cpp
#include "stdafx.h"
void main()
{
}
//stdafx.h
#pragma once
#include "A.h"
#include "B.h"
编译option里,对main.cpp指定/Yu'stdafx.h',表示对main.cpp使用预编译头文件。
这样的话,A.h和B.h会被预编译到.pch里,main.cpp会使用这个.pch。
预编译头文件的更新
上面其实隐藏着一个问题:如果B里用到的是A的实例的话,A.h一旦改变,B这个class,以及main.cpp都应当重新编译的。如果如上述这样使用了预编译头文件,A.h改变后,没有任何东西会被重新编译。这是因为对main.cpp指定的是Yu,即使用,而不是生成.pch,所以估计VC会忽视stdafx.h以及被它所include的A.h和B.h的timestamp。VC其实是这么做的,默认的,还会有一个stdafx.cpp。
//stdafx.cpp
#include "stdafx.h"
这个文件的编译option是/Yc 'stdafx.h',也就是生成预编译头文件。对这个option,VC不会忽略其include的文件的timestamp,所以,一旦A.h发生了变化,这个文件及它所include的头文件都会被重新编译,重新生成.pch。
gcc的话,没有这样的option。编译器所作的只是在编译头文件之前先去找和头文件名称相同的.gch文件而已。和其他obj文件一样,预编译头文件的更新,通过makefile做。
0 件のコメント:
コメントを投稿