Preheader文本(即precompiledheader,预编译头)位于邮件顶端及邮件内容之上,之所以称其为"Preheader文本",是因为其位于邮件头部(header),即LOGO和导航的以上部位。
在计算机编程中,预编译头文件是一个(C或C ++)头文件,它被编译成中间格式,编译器处理速度更快。 预编译头的使用可能会大大减少编译时间,特别是应用于大型头文件,包含许多其他头文件的头文件或包含在许多翻译单元中的头文件时。
介绍
在C和C ++编程语言中,头文件是文件可以由C预处理器通过在源文件中使用预处理器指令自动包含在另一个源文件中的文件。
头文件有时可能包含非常大量的源代码(例如,分别在Microsoft Windows和OS X上的头文件windows.h和Cocoa / Cocoa.h)。特别是在大量使用模板的大型“头文件”库(如特征数学库和Boost C ++库)的出现时尤其如此。它们几乎完全是作为用户#includes的头文件编写的,而不是在运行时链接。因此,每次用户编译他们的程序时,用户基本上也重新编译了许多头库。(这些将被预编译到非“标题”库中的共享对象或动态链接库中。)
为了减少编译时间,一些编译器允许将头文件编译成更快的编译器处理形式。这个中间表单被称为预编译头文件,通常保存在一个名为.pch扩展名或类似文件的文件中,例如GNU编译器集合下的.gch。
用法
例如,给定一个包含header.hpp的C ++文件source.cpp:
//header.hpp...//source.cpp#include "header.hpp"...
第一次编译source.cpp时,编译器会生成一个预编译头header.pch。 下一次,如果此标头的时间戳没有改变,编译器可以跳过与header.hpp相关的编译阶段,而是直接使用header.pch1。
常见的实现Microsoft Visual C和C ++
Microsoft Visual C ++(版本6.0和更新[需要的引证])可以预编译任何代码,而不仅仅是头文件。它可以通过两种方式实现:预编译所有代码,直到名称与/ Ycfilename选项匹配的文件或(当/ Yc指定为不带任何文件名时)预编译所有代码,直到代码中第一次出现#pragma hdrstop 预编译的输出保存在一个文件中,该文件的名称以给定给/ Yc选项的文件名,扩展名为.pch或者根据/ Fpfilename选项提供的名称命名的文件中。 / Yu选项,如果与/ Yc选项一起使用,会使编译器使用来自此文件的已编译好的代码。
stdafx.h是由Microsoft Visual Studio IDE向导生成的文件,它描述了经常使用但几乎不会更改的标准系统和项目特定包含文件。
兼容的编译器将预编译此文件以减少总体编译时间。除非编译选项/Yu'stdafx.h未选中(默认情况下),否则Visual C ++不会编译源文件中的#include“stdafx.h”之前的任何内容。它假定源中包含该行的所有代码都已编译。
stdafx.h中的afx代表应用程序框架扩展。 AFX是Microsoft基础类(MFC)的原始缩写。虽然名称stdafx.h是默认使用的,但项目可以指定一个替代名称。
clang
clang编译器有两种机制。
原始的,简单的和不太强大的机制是pretokenized标头,其中一个或多个源文件中的词汇标记流存储在有效的标记缓存中,从而可以在后续汇编中更快地检索它们,而不是执行词法分析再次在原始源文件。
与完整的预编译头部机制相比,这具有语言独立性的优势,因为词法分析在C,C ++,Objective C和Objective C ++语言的铿锵声中是相同的,并且与架构无关,因为可以使用相同的令牌流在编译不同的目标架构时。然而它的缺点是没有进行简单的词法分析,需要对每个汇编执行令牌流的句法和语义分析;以及用预先编写的文件的词法标记的大小线性地进行缩放编译的时间,这对于完全成熟的预编译机制不一定是这种情况。
预清除机制包括几个辅助预处理器的小机制:缓存文件存在和日期戳记信息,以及记录包含警告,以便可以快速跳过守护的代码。
因此后来的clang开发引入了完全成熟的预编译头部机制。这既标记输入源代码,也执行语法和语义分析,将编译器的内部生成的抽象语法树(AST)和符号表写入预编译的头文件中。
与pretokenized头文件机制相比,这种扩展性好得多,因为在编译器中读取预编译头文件时,不受输入是线性读取文件流的影响(使用词法标记),使用顺序I / O. [5] AST被写入预编译头文件,编译器可以使用随机访问I / O来读取它,特别是不读取预编译AST中后面的代码实际上没有引用的部分,这是常见的头文件提供大型模板库。这消除了读取缓存文件与预编译输入大小线性缩放的问题。
然而,不利的一面是,相比于pretokenization机制,普遍性的损失。预编译头文件必须存储关于正在使用的语言方言的信息,直到是否在非C ++语言,目标体系结构,编译器版本(更具体地说是编译器正在使用的内部AST数据结构)以及预定义的预处理器宏列表;所以在重新读取预编译的头文件时,编译器可以确保它使用了一个对编译有效的预编译头。
clang的预编译头部方案,并且具有一些改进,例如一个预编译头部引用另一个内部使用的预编译头部的能力,也构成了其模块机制的基础。它使用LLVM采用的相同位码文件格式,封装在通用对象文件格式或可扩展链接格式文件中的特定于文本的段中2。
GCC
预编译头文件在GCC(3.4及更高版本)中受支持。 GCC的方法类似于VC和兼容编译器。 GCC使用“.gch”后缀保存预编译头文件的版本。编译源文件时,编译器会检查此文件是否存在于同一目录中,并尽可能使用它.
GCC只能使用预编译版本,如果设置相同的编译器开关,则编译头文件时最多可使用一个。此外,只有预处理指令可以放在预编译头之前(因为在任何可编译的代码之前它必须直接或间接地通过另一个正常头包含)。
GCC通过扩展自动识别大多数头文件。但是,如果失败(例如由于非标准扩展头),可以使用-x开关确保GCC将文件视为标头。
C ++ Builder
在缺省项目配置中,C ++ Builder编译器隐式地为源模块包含的所有头生成预编译头文件,直到找到#pragma hdrstop行。如果可能的话,预编译头文件将为项目的所有模块共享。例如,使用Visual Component Library时,通常首先包含vcl.h头文件,其中包含大多数常用的VCL头文件。因此,可以在所有项目模块之间共享预编译头文件,这大大缩短了编译时间。
另外,可以将C ++ Builder作为预编译头文件使用特定的头文件,类似于Visual C ++提供的机制。
C ++ Builder 2009引入了一个“预编译头文件向导”,它解析项目的所有源模块以包含头文件,对它们进行分类(即,如果头文件是项目的一部分或不包含头文件,则不包括头文件),并生成自动测试指定文件的预编译头。
本词条内容贡献者为:
李岳阳 - 副教授 - 江南大学

扫码下载APP
科普中国APP
科普中国
科普中国