6

在阅读了这篇好文章(预编译头文件的护理和提供)之后,我对这些如何在现实生活中实际工作有一些疑问。更具体地说,我怎么知道我需要在以下场景中触发预编译头的重建:

  • 我决定#define在我的一个 .cpp 文件中更改预处理器解释一些已包含在我的预编译头文件中的头文件的方式
  • 我在我的一个 .cpp 文件中包含另一个头文件,它#define是一个特定的预处理器指令,它改变了预处理器解释已包含在预编译头文件中的头文件的方式
  • 更糟糕的是,上一个问题可能会递归地发生,当某些标头#include其他标头时

预编译头文件的使用是否应该强制执行某种限制性编码样式,例如将 .cpp 文件中包含的头文件数量限制为一个,并且永远不会#define在 .cpp 文件中添加内容?

虽然 Microsoft 的编译器可能在预编译头文件方面做得不错(通过应用一些特定于 MS 的巫术),因为据我所知,它提供了应该完成所有工作的/Yc/Yu选项,但对于 GCC 来说,这似乎是功能需要在 Makefile 中进行大量手动工作和创造力,我无法找到一个可以解决使用预编译头文件的所有缺陷的模板。

例如,如果我有一个构建多个库的项目,为了不在每次更改后重新构建所有库,我必须在 Makefile 中使用一些非常可爱的sed技巧来检测#include当前库的头文件之一是否被修改(或者它#include是修改后的标题)。我什至害怕想到预先构建的标头实际上会暗示的复杂性,以便构建脚本在每次有必要时都重新构建它们。

4

1 回答 1

15

当前的 GCC(即 4.7)和它的早期版本只有在您的应用程序有一个公共头文件时才能很好地与预编译头文件一起使用,并且当需要该单个头文件(依次包括所有系统头文件和库特定头文件时)由应用程序)是-d (作为您的源代码的第一个非注释词位)由您的应用程序的每个源代码。#include

因此,您应该有一个单一 yourapp.h的 并且每个源文件(即每个编译单元)都以命令行上相同的预处理选项(即or或)yourapp 开头。该头文件通常包含许多其他头文件,例如系统头文件(或 GTK 或 Qt 头文件),如or或 [在 C++ 中]或等。#include "yourapp.h"-D-I-Uyouapp.h#include<stdlib.h><sys/poll.h><algorithm><gtk/gtk.h><QtGui>

回想一下,这-H是一个有用的选项,可以gcc告诉您包含的内容。

如果需要,您的源文件可能会有一些额外的#include 内容 #include "yourapp.h"

在 GCC 包含一个 [single] 预编译头文件后,您当然可以使用#define宏、#include一些非预编译头文件、使用 进行条件编译#ifdef等。但该预处理不会被“预编译”!

这可能不符合您的需求或习惯。

一些人(特别是来自 Google,特别是 Diego Novillo)正在开发PreParsed Header (pph) 分支以改善这种情况,但当前的 GCC 主干还没有完成这项工作。

关于 GCC 的这种行为的解释是,预处理标头本质上是整个 GCC 堆的持久序列化检查点(通过 Ggc 和 GTY 与 GCC 内部的内存管理gengtype相关)。gcc只有当处于初始空状态时,才能加载该检查点堆。一旦gcc(实际上cc1cc1plus)已知某些内容,它就不能再加载任何预编译的头文件*.h.gch,并将恢复解析文本头文件*.h


附录(2014 年 11 月及以后)

甚至GCC 4.9也需要一个预编译头文件。Diego Novillo 等人的预解析标头工作。已被遗弃。

C++ 标准的未来版本(C++14之后)可能会定义模块机制。参见例如n4047提案和C++20标准。

(附加附录,2020 年夏季)这仍然适用于存在多个静态分析器选项的GCC-10 。另请参阅Clang 静态分析器此报告草案。考虑使用Frama-C

于 2012-09-15T14:04:44.540 回答