为什么要使用预编译头文件(C/C++)?

52

为什么要使用预编译头文件?


阅读回复后,我怀疑我一直在使用它们的方式有点愚蠢:

#pragma once

// Defines used for production versions

#ifndef PRODUCTION
#define eMsg(x) (x) // Show error messages
#define eAsciiMsg(x) (x)
#else
#define eMsg(x) (L"") // Don't show error messages
#define eAsciiMsg(x) ("")
#endif // PRODUCTION

#include "targetver.h"
#include "version.h"

// Enable "unsafe", but much faster string functions
#define _CRT_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_WARNINGS

// Standard includes
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <direct.h>
#include <cstring>
#ifdef _DEBUG
#include <cstdlib>
#endif

// Standard Template Library
#include <bitset>
#include <vector>
#include <list>
#include <algorithm>
#include <iterator>
#include <string>
#include <numeric>

// Boost libraries
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/scoped_array.hpp>

//Windows includes
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "FILETIME_Comparisons.h"
#include <shlwapi.h>
#include <Shellapi.h>
#include <psapi.h>
#include <imagehlp.h>
#include <mscat.h>
#include <Softpub.h>
#include <sfc.h>
#pragma comment(lib, "wintrust.lib")
#pragma comment(lib,"kernel32.lib")
#pragma comment(lib,"Psapi.lib")
#pragma comment(lib,"shlwapi.lib")
#pragma comment(lib,"imagehlp.lib")
#pragma comment(lib,"Advapi32.lib")
#pragma comment(lib,"Shell32.lib")
#pragma comment(lib,"Sfc.lib")
#pragma comment(lib,"Version.lib")

// Crypto ++ libraries
#ifdef _DEBUG
#pragma comment(lib,"cryptlibd.lib")
#else
#pragma comment(lib,"cryptlib.lib")
#endif
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include <md5.h>
#include <sha.h>

// String libraries
#include "stringUnicodeConversions.h"
#include "expandEnvStrings.h"
#include "randomString.h"
#include "getShortPathName.h"

// Regular Expression Libraries
#include "fpattern.h"

// File Result Record
#include "unixTimeToFileTime.h"
#include "fileData.h"

// Writer
#include "writeFileData.h"

// Criteria Structure System
#include "priorities.h"
#include "criterion.H"
#include "OPSTRUCT.H"
#include "regexClass.H"
#include "FILTER.h"

// Sub Programs Root Class
#include "subProgramClass.h"

// Global data
#include "globalOptions.h"

// Logger
#include "logger.h"

// Console parser
#include "consoleParser.h"

// Timeout handler
#include "timeoutThread.h"

// Zip library
#include "zip.h"
#include "unzip.h"
#include "zipIt.h"

// Scanner
#include "mainScanner.h"
#include "filesScanner.h"

// Sub Programs
#include "volumeEnumerate.h"
#include "clsidCompressor.h"
#include "times.h"
#include "exec.h"
#include "uZip.h"

// 64 bit support
#include "disable64.h"

3
关于Visual Studio的一个重要提示:确保每个头文件的第一个#include是#include "stdafx.h",否则你的文件将无法被解析!这很蠢,但这是一个容易犯的错误。 - rlbond
2
更具体地说,#include "stdafx.h" 以上的任何内容都不会被解析。请参见http://en.wikipedia.org/wiki/Precompiled_header。 - rlbond
5个回答

72
在C/C++中,#include机制会将指定文件以文本形式复制到当前文件中。头文件可以包含其他头文件(可能还包括其他头文件),所以每次使用 #include 时,都可能向每个cpp文件(或cxx、c等)添加数万行 C++ 代码,并且需要每次编译所有这些代码。对于大型项目来说,这可能成为一个严重的瓶颈。
预编译头文件可以通过只编译每个头文件一次,然后将编译好的状态包含到它们所包含的cpp文件中,从而加速编译过程。

1
我正在研究一下预编译头文件到底是什么,因为我们知道头文件本身并不是一个翻译单元。很好的解释,谢谢。 - macroland
很好的简要解释。这应该被标记为答案。 - Everyone
1
“编译每个头文件一次”的意思是什么?头文件会被编译吗?它们只是声明而已,不是吗? - TonySalimi
@Gupta 声明(例如 int foo(int a, int b))也需要被编译器“编译”处理。除此之外,与 C 语言中的头文件不同,C++ 中的头文件往往包含实际代码(这可能不是最好的想法)。特别是在考虑到模板时,通常必须将其放置在头文件中。 - Aviv Cohn
如果我的项目只有一个.cpp文件,并且包含预编译头文件,那么在这种情况下使用预编译头文件会加快编译速度吗? - mercury0114
如果您经常更改 .cpp 文件但未更改相应的 .h 文件,则仍可能受益于预编译头文件。只需将所有的 #include 行放在 foo.h 中,并且仅在 foo.cpp 中包含 #include "foo.h" - Bodo Thiesen

43

使用预编译头文件编译速度会更快。如果没有它们,C++编译需要很长时间,甚至可能需要数年。在大型项目中尝试比较一下时间吧!


2
如果一个项目很小,少于10个文件,是否仍应该使用预编译头文件? - Danijel
1
文件有多大? - KcFnMi
1
@Danijel 你应该自己检查一下。如果你切换到预编译头文件并重新编译几次,发现没有明显的区别,那么这是没有意义的。如果你能够在不看时钟的情况下感觉到它编译得更快,那么是的,你应该使用它们。 - user11877195

12

关于你当前的使用情况,如果你的目标有大量文件,使用PCH可能仍然更快 - 尝试关闭它们以找出结果。这取决于:如果你有很多自己的头文件,并且很少更改它们,并且你有非常多需要更频繁更改的源文件,那么使用PCH将可以减少重新构建的时间。

但是正常的建议是只将永远不会更改的东西放在PCH中,因为制作PCH本身会有一定的开销。如果你通过不断调整其中一个头文件来触发每次重新构建(触发PCH重建),那么使用PCH可能会使重新构建变慢。


这些文件在每次构建中都会发生相当大的变化 :P - Billy ONeal

7

因此,您不必在每次构建项目时编译它们。它们用于系统头文件,这些文件不会更改。


7

它可以加速编译。

当你包含其他项目的头文件时,你不希望改变它们。如果你将它们放入预编译头中,当你修改源代码时,这些代码将不必重新编译。这减少了重复编译未更改代码的时间,从而加快了编译速度。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接