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

时间:2013-05-31 06:42:33

标签: c++ header g++

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

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

3 个答案:

答案 0 :(得分:4)

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

#ifndef MY_HEADER_H
#define MY_HEADER_H

// header body...

#endif MY_HEADER_H

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

编译器可能足够聪明,可以避免多次读取文件。但是,即使它没有,操作系统也非常擅长缓存最近读取的文件,这将非常快速地加载 - 几乎不需要任何费用。

答案 1 :(得分:4)

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

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

唯一不适用的情况是头文件是否包含#pragma once语句。一些编译器对包含保护的用户进行了类似的优化:

#ifndef THIS_FILE_H
#define THIS_FILE_H 1
/* the stuff in thisfile.h */
#endif

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

通常,这是通过将.h或.cpp文件包含在您的所有#include中来完成的。然后在每个文件中首先#include此文件(或使用'强制包含'的概念:/ ms在msvc中, - 包括gcc)。使用给定pch的每个文件都必须具有相同的定义和编译器选项。

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

// bah.h
"bah",

以及以下.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;
}

输出为

hello
bah
world
bah
bah

答案 2 :(得分:1)

预处理器 简单地替换每个源文件中的宏定义,在此之后, < em>编译器 将开始将每个源文件编译为独立的汇编文件,然后由 汇编程序 将其转换为二进制机器代码。 链接器 最后会将所有目标文件链接到一个已执行文件共享对象。< / p>

因此,它基本上不属于预处理过程中编译器的业务。而g ++是一组工具,包括预处理器,编译器,链接器。