我正在读一本关于Applied C ++的书。
包含防护将阻止更多地包含头文件 在编译源文件期间不止一次。你的符号名称 应该是唯一的,我们建议根据名称选择名称 的文件。例如,我们的文件cache.h包含这个包含 后卫。
#ifndef _cache_h_
#define _cache_h_
...
#endif // _cache_h_
Lakos描述了使用冗余包含警戒来加速 汇编。见[Lakos96]。对于大型项目,打开需要一些时间 每个文件,只发现包含保护符号已经存在 已定义(即文件已包含在内)。对...的影响 编译时间可能是戏剧性的,Lakos显示可能的20倍 当只有标准包括警卫时,编译时间会增加 使用
[Lakos96]:LargeScale C ++软件设计。
我没有Lakos96参考书来提及概念,所以在这里寻求帮助。
我对上述文字的疑问是
作者的意思是“对于大型项目,打开每个文件需要花费时间,但却发现已经定义了包含保护符号”?
作者的意思是“当使用标准包括警卫时”?
感谢您的时间和帮助。
答案 0 :(得分:8)
来自C ++编码标准(Sutter,Alexandrescu)
许多现代C ++编译器自动识别标题保护(参见 项目24)并且甚至不打开两次相同的标题。有些还提供 预编译的头文件,有助于确保经常使用的, 经常不会解析很少更改的标题
所以,我会认为这些建议已经过时了(除非你还在使用一些非常过时的编译器)。
关于你的问题:
什么是冗余编译保护?
天真的编译器会在每次包含文件时重新加载文件。至 避免这种情况,将RedundantIncludeGuards放在include:header.h
周围
#ifndef HEADER_H_
#define HEADER_H_
// declarations
#endif
foo.c的
#ifndef HEADER_H_
#include "header.h"
#endif
了解更多here。您的参考声称通过这样做,您可以在编译期间比foo.c仅执行时快20%
#include "header.h"
答案 1 :(得分:6)
我不知道Lakos96说的是什么,但无论如何我都要猜测......
标准包括警卫就像:
#ifndef FOO_H_INCLUDED
#define FOO_H_INCLUDED
....
#endif
冗余include guard在包含文件时使用宏:
#ifndef FOO_H_INCLUDED
#include "foo.h"
#endif
这样第二次包含foo.h
文件时,编译器甚至不会在磁盘中搜索它。因此加速:想象一个大项目,一个单独的编译单元可能包括foo.h
100次,但只有第一个将被解析。其他99次将被预编译器搜索,打开,标记化,丢弃并关闭。
但请注意那是在1996年。今天,GCC提供了一个众所周知的例子,它具有特定的优化功能,可识别包含保护模式,并使冗余包括保护,嗯......,冗余。
答案 2 :(得分:5)
Herb Sutter,C ++大师,现任ISO C ++标准主席 委员会,反对外部包括警卫:
“顺便说一句,我强烈反对拉科斯的外部包括警卫 基于两个理由:
大多数编译器都没有任何好处。我承认我还没有做过测量,因为当时Lakos似乎做过,但就我而言 知道今天的编译器已经有了智能,以避免构建时间 重读开销 - 甚至MSVC都做了这个优化(虽然它 要求你说“#pragma once”),它是最弱的编译器 很多方式。
- 醇>
外部包含守卫违反封装,因为它们需要许多/所有呼叫者知道标头的内部 - 在 特别是,用作守卫的特殊#define名称。他们也是 脆弱 - 如果你的名字错了怎么办?如果名称改变怎么办?“
答案 3 :(得分:1)
在一个大型项目中,可能有许多标题 - 可能是100个甚至1000个文件。在正常情况下,每个标题内都包含保护,编译器必须检查(但见下文)文件的内容,看它是否已被包含。
标题内的这些警卫是“标准”。
Lakos建议(对于大型项目)将守卫放在#include
指令周围,这意味着如果已经包含了标题,则甚至不需要打开标题。
据我所知,所有现代C ++编译器都支持#pragma once
指令,它与预编译的头文件相结合意味着在大多数情况下问题不再是问题。
答案 4 :(得分:0)
我认为它所指的是在头文件之外复制包含保护,例如
#ifndef _cache_h_
#include <cache.h>
#endif
但是,如果这样做,您将不得不考虑标题保护有时会在文件中发生变化。你肯定不会在现代系统中看到20倍的改进 - 除非你的所有文件都在一个非常远程的网络驱动器上 - 但是你可以通过将项目文件复制到本地驱动器来获得更好的改进! / p>
前面有一个类似的问题,关于“包括冗余文件”(指多次包含头文件),我构建了一个包含30个源文件的小型系统,包括<iostream>
“不必要”,编译时间的整体差异在包括<iostream>
和不包括{{1}}之间为0.3%。我相信这一发现表明GCC的改进是“自动识别不包含任何内容的文件,包括警卫”。
答案 5 :(得分:0)
在人数较多的大型项目中,可能会有一个处理时间转换的模块,作者可以选择使用TIME
作为后卫。然后你将有另一个处理精确计时,它的作者,不知道第一个,也可以选择TIME
。现在你发生了冲突。如果他们使用TIME_TRANSFORMATION
和PRECISE_TIMING_MODULE
,他们就可以了
不知道。我猜它可能意味着“当你每次都这样做时,它始终是你的编码标准”。