为什么要包括警卫?

xim*_*mus 15 c c++ compiler-construction gcc preprocessor

这里定义的包含保护用于防止在编译时加载相同的代码两次.

为什么我的编译器(GCC)无法检测到它正在加载相同的代码两次并且具有合理的默认行为?

Spo*_*ook 18

只是因为您可能希望编译器加载该文件两次.

请记住,它#include只是加载文件并将其内容放在指令的位置.此文件可能是头文件,但也可能是有用且经常使用的源代码.

大多数现代编译器都会根据#pragma once您的需要做出反应.但请记住,这是一个未包含在语言规范中的编译器扩展,并且坚持包含保护通常是一个好主意 - 您可以肯定,它适用于每个编译器和任何情况.

  • 存在无法检测两个包含是否指向同一文件的情况.它们不会出现在简单的独立系统中(至少不是我所知道的),但是一旦你开始联网就可以(并且在实践中,尽管很少).该委员会实际上讨论了制定`#pragma once`标准,并拒绝它,因为它不是(可靠的)可实现的. (2认同)
  • @Roddy不仅仅是来自符号链接---至少在Unix下,有办法解决这个问题.但是当导入的文件系统安装在两个不同的位置时.(奇怪的是,这种情况发生的次数比人们预期的要多.) (2认同)

Mik*_*our 12

为什么我的编译器(GCC)无法检测到它正在加载相同的代码两次

它可以(或者,迂腐地处理头部包含的预处理器).您可以使用非标准但广泛支持的扩展,而不是使用包含保护

#pragma once
Run Code Online (Sandbox Code Playgroud)

表示此标题只应包含一次.

并有一个合理的默认行为?

默认情况下,该语言未指定此行为,主要是因为语言可追溯到跟踪包含的标头可能非常昂贵的时间,部分原因是有时您确实想要多次包含标头.例如,<assert.h>可以在NDEBUG定义或不定义的情况下重新排列标准头,以更改assert宏的行为.


Rod*_*ddy 9

因为存在重新包含文件有用的奇怪边缘情况.

受骗的丑陋示例:假设您有一个这样的#include文件mymin.h:

// mymin.h : ugly "pseudo-template" hack
MINTYPE min(MINTYPE a, MINTYPE b)
{
   return (a < b) ? a : b;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以做这样的事情:

#define MINTYPE int
#include "mymin.h"

#define MINTYPE double
#include "mymin.h"
Run Code Online (Sandbox Code Playgroud)

现在,您有两种min不同类型的重载,并且是http://thedailywtf.com/的良好候选者.谁需要模板?;-)

请注意,许多现代预处理器都支持#pragma once,这是实现与包含警卫相同效果的更好方法.然而,遗憾的是它不合标准.