c++程序中多个源文件中的相同头文件

Bir*_*ora 5 c++ g++ header

如果同一个头文件包含在一个 c++ 程序中的多个源文件中,那么它如何影响编译(尤其是g++)?

编译器是只加载一次头文件并为每个包含头文件的源文件编译它,还是为每个包含它的源文件单独加载头文件。

kfs*_*one 6

与 g++ 对话:#includes 是由预处理器完成的,而不是编译器本身。使用g++的switch可以看到预处理的结果-E。(编辑:预处理器曾经是独立的,但现在是编译器可执行文件的一部分,但是为了回答这个问题,预处理阶段仍然是编译过程的一个不同阶段)。

对于 gcc、clang、icc 和 msvc,每个文件每次遇到时都会被访问,即使在同一个源文件中也是如此。

唯一不正确的情况是头文件包含语句#pragma once。一些编译器对 include-guards 的用户有类似的优化:

#ifndef THIS_FILE_H
#define THIS_FILE_H 1
/* the stuff in thisfile.h */
#endif
Run Code Online (Sandbox Code Playgroud)

msvc 和 gcc(可能还有 clang)支持一种称为“预编译头”的技术,它可以与您一起避免常用头集的编译头。

#include通常,这是通过包含所有内容的.h 或 .cpp 文件来完成的;然后#include在每个文件中首先使用此文件(或使用“强制包含”的想法:msvc 中的 /Fi,gcc 中的 -include)。使用给定 pch 的每个文件都必须具有相同的定义和编译器选项。

如果你要编写以下.h文件

// bah.h
"bah",
Run Code Online (Sandbox Code Playgroud)

和以下 .cpp 文件

#include <stdio.h>

const char* words[] = {
    "hello",
#include "bah.h"
    "world",
#include "bah.h"
#include "bah.h"
    NULL
};

int main(int argc, const char* argv[])
{
    for (size_t i = 0; words[i] != NULL; ++i ) {
        printf("%s\n", words[i]);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出将是

你好
呸
世界
呸
呸

  • “对于 `g++`:`#include`-s 由预处理器完成”并不完全正确:多年来,`g++` 正在启动 `cc1plus`,它是一个进行预处理的单个程序,解析、优化、代码排放......预处理由编译器(`cc1plus`)完成,而不是单独完成。(这是 20 世纪 90 年代海湾合作委员会的一个单独进程)。 (2认同)
  • 这在很久以前是正确的……但在今天却是错误的。`cc1plus`(来自 GCC 4.x)正在链接一个内部库 `libcpp`,它执行预处理和一些标记化。预处理过程中(就在解析之前)增量地进行......GCC 不能通过一次性全部预处理,然后解析预处理后的形式来工作(即使它看起来是这样工作的)。 (2认同)

mvp*_*mvp 4

大多数头文件都有针对多个包含的特殊保护,例如

#ifndef MY_HEADER_H
#define MY_HEADER_H

// header body...

#endif MY_HEADER_H
Run Code Online (Sandbox Code Playgroud)

如果没有这种保护,标头可能会被包含多次,这可能会导致编译或链接错误。

编译器可能足够聪明,可以避免多次读取文件。但是,即使没有,操作系统也非常擅长缓存最近读取的文件,并且加载速度非常非常快 - 几乎没有任何成本。

  • 如果您阅读这个问题,它是关于在多个源文件中包含标头。单个源文件中不能包含多个内容。我很确定您没有回答所提出的问题,而是提出了一个类似的问题,但答案却完全不同。 (3认同)