pragma once、include防范、包括警卫优化

这个页面来自对comp.lang.c ++的讨论。关于在C或C ++程序中#including头文件的最有效方式。通常,每个头文件只应为#included一次。在一个中等大小的项目中,头文件#include其他头文件,如果没有某种形式的自动化帮助,很难保持这个规则。一个常见的习惯用法是在包含的头文件的内容周围放置“包含警卫”。例如

档案“myheader.hpp”

#ifndef MYHEADER_HPP 
#define MYHEADER_HPP 


//包含文件的内容到这里

#endif

因此,即使文件多次#included,其内容也只会被处理一次。这被称为内部包含保护,因为保护完全在头文件的内部。

这种方法的一个问题是,如果编译器采用天真的方法,它仍然必须多次打开文件以检查内部包含保护。在大型项目中,这可能会导致编译时间增加。这一点由John Lakos在他的“大规模C ++软件设计”一书中提出,并用作支持以下习语的论据:

档案“myheader2.hpp”

#ifndef MYHEADER_HPP 
#include“myheader.hpp” 
#endif 


//其余的头文件都在这里

保护符号(MYHEADER_HPP)仍在内部定义和检查,但是通过外部检查保护符号,编译器可能完全不必打开头文件。建议只有当其他头文件中包含头文件时才进行此外部检查 - 当文件从源文件中包含#included时,可以省略外部检查。内部保护用于保证正确性,外部保护增加编译速度。所涉及的成本是将检查放在每个头文件#included在另一个头文件中,并正确拼写保护符号的名称。

事实证明,一些编译器将允许我们通过实施“包含保护优化”来获得我们的蛋糕并吃掉它。

什么是包含警卫优化?

包含保护优化是指编译器识别上述内部包含保护惯用语并采取措施避免多次打开文件。编译器可以查看包含文件,删除注释和空格,并确定整个文件是否在包含保护范围内。如果是,则存储文件名并在地图中包含保护条件。下次要求编译器包含该文件时,它可以检查包含保护条件并决定是否跳过该文件或#include它而不需要打开该文件。

由于并非所有编译器都实现了这种优化,因此我将基准测试放在一起以便检查优化。还有一个结果页面可供您查找给定的编译器。

基准如何运作?

该基准测试使用两个头文件 - 一个带有内部包含防护,另一个没有:

guard.h noguard.h
#ifndef GUARD_H 
#define GUARD_H 
extern int i; 
#万一
extern int i;

然后三个C源文件#include这些头文件多次:

 

  • 外部包括警卫
    #ifndef GUARD_H 
    #include“guard.h” 
    #endif 
    #ifndef GUARD_H 
    #include“guard.h” 
    #endif 
    #ifndef GUARD_H 
    #include“guard.h” 
    #endif 
    #ifndef GUARD_H 
    #include“guard.h” 
    #endif 


    这应该快速编译,因为头文件只需要打开一次。

  • 没有包括警卫
    #include“noguard.h” 
    #include“noguard.h” 
    #include“noguard.h” 
    #include“noguard.h” 


    这应该编译得很慢,因为头文件必须多次打开。请注意,在实际代码中,同一头文件的多个包含几乎肯定会导致违反一个定义规则。这个文件对于基准测试仍然有效且必要,因为它为我们提供了一个“上限”时间 - 它告诉我们如果编译器被迫多次打开头文件,编译将花费多长时间。

  • 内部包括警卫
    #include“guard.h” 
    #include“guard.h” 
    #include“guard.h” 
    #include“guard.h” 


    如果实现内部包含保护优化,则这将快速编译,因为头文件只需要打开一次(如在外部包含保护的情况下)。如果没有实现优化,这将编译缓慢,如在无包含保护的情况下。

 

为了获得足够大的时间来容易测量,包含的数量需要很大(几千)。可以从下载部分获取示例测试文件和生成它们的软件 。

你可能感兴趣的:(学习与知识)