为什么不';t c+中包括防护装置+;默认值? 我使用Apple TracMA曾经(或者在我的C++项目中的每一个头文件中基本上都使用了包含CARS的代码“La>代码>IFNDEF…”。这是巧合还是你在大多数开源项目中发现的(避免只依赖个人项目经验的答案)。如果是这样,为什么不是相反的:如果我想把头文件包含好几次,我使用一些特殊的预处理器命令,如果不是,我把文件保留为.< /p>

为什么不';t c+中包括防护装置+;默认值? 我使用Apple TracMA曾经(或者在我的C++项目中的每一个头文件中基本上都使用了包含CARS的代码“La>代码>IFNDEF…”。这是巧合还是你在大多数开源项目中发现的(避免只依赖个人项目经验的答案)。如果是这样,为什么不是相反的:如果我想把头文件包含好几次,我使用一些特殊的预处理器命令,如果不是,我把文件保留为.< /p>,c++,C++,,根据如何处理每个翻译单元来指定C++编译器的行为。翻译单元是预处理器在其上运行后的单个文件。我们有一个约定,在某些文件中收集声明并称它们为“头”文件,这对于编译器或C++标准来说是没有意义的。 简单地说,该标准没有提供“头文件”,因此它不能提供自动包含保护头文件。该标准仅提供预处理器指令#include,其余仅为惯例。没有什么能阻止您转发声明所有内容和不使用头文件(除了可怜应该维护代码的人…) 所以头文件不是特别的,也没有办法说“那是头文件,保护它”,但是为什么我们不能保护所有得到的#包括'd

,根据如何处理每个翻译单元来指定C++编译器的行为。翻译单元是预处理器在其上运行后的单个文件。我们有一个约定,在某些文件中收集声明并称它们为“头”文件,这对于编译器或C++标准来说是没有意义的。 简单地说,该标准没有提供“头文件”,因此它不能提供自动包含保护头文件。该标准仅提供预处理器指令
#include
,其余仅为惯例。没有什么能阻止您转发声明所有内容和不使用头文件(除了可怜应该维护代码的人…)

所以头文件不是特别的,也没有办法说“那是头文件,保护它”,但是为什么我们不能保护所有得到的
#包括
'd的东西呢?因为像其他语言一样,
#include
比模块系统的功能更强大,也更弱
#include
导致预处理器粘贴到其他文件中,而不一定是头文件。有时,如果在不同的文件中的一组不同名称空间中有相同的using和typedef声明,这可能会很方便。您可以将它们收集到一个文件中,并将它们包含在一些地方。你不会希望自动包含阻止你这样做的守卫

使用
#ifndef
#define
有条件地包含标题也是惯例。本标准没有“包括防护装置”的概念。(然而,现代编译器实际上知道包含防护。识别包含防护可以加快编译速度,但与正确实现标准无关。)

变得迂腐

标准使用了“头”字,特别是在C和C++标准库中。但是,

#include
的行为是在
§16.2*源文件*包含
(emph.mine)中定义的,它不授予头文件任何特殊权限


<> P. >在C++标准中,有一个适当的模块系统。

< P>因为歇斯底里葡萄干。

< C++预处理器与C预处理器几乎相同,它是在40年前设计的。当时的编译器要简单得多。预处理器更简单,只是一个愚蠢的宏处理器,甚至不是编译器。尽管C++标准没有指定标准头的工作原理,但概念<>代码>包含> <代码>仍然与40年前相同:它使预处理器将命名文件的内容插入到包含文件中。 在一个没有大量相互依赖关系和子模块的简单C代码库中,可能不需要包含保护。早期的预标准C没有使用函数原型,这正是现在大多数include文件所使用的。如果两次包含头导致错误,您可能会重新安排代码以防止它被包含两次

随着代码库的增长和变得越来越复杂,我认为意外地包含两个头(可能是间接地,通过其他头)的问题变得越来越常见。一种解决方案是改变预处理器,使其更智能,但这需要每个人都使用新的预处理器,并使其更大、更慢。因此,开发了一种使用预处理器现有功能(
#define
#ifndef
)解决问题的约定,不是通过防止头被包含两次,而是通过简单地使头被包含两次无害,因为它在第一次被包含后没有任何效果

随着时间的推移,该约定得到了越来越广泛的应用,现在几乎是通用的,除了少数几个设计为包含两次并以这种方式正确编写的标题示例(例如

后来,一些编译器引入了一种替代的、不可移植的方式,使其具有与include-guard相同的效果,即
#pragma once
,但到那时,世界各地使用的各种C预处理器都有数千个副本,include-guard已成为常态


因此,目前的行为几乎肯定是由于历史原因。今天编写的现代语言,对于今天功能强大的计算机来说,如果从头开始设计,就不会使用像C预处理器这样的东西。但C不是在21世纪设计的。我认为include-guard约定是随着时间的推移慢慢建立起来的,不需要对现有软件进行任何更改就可以工作。现在改变它会打破依赖于当前行为的未知数量的C和C++代码,这可能不是一个选项,因为向后兼容性对于C和C++都很重要。

< P>我必须同意,主要因素是历史,偶尔说,你会看到代码依赖于它们而不存在。MAME就是一个例子:它从一个可读的基于宏的文件中构建复杂的数据结构(或者至少是我上次看到的,不久前),方法是多次将其包含在定义不同的宏中。如果include-guard是自动的,你会遇到需要关闭它们的代码。

\35; pragma-once
不是标准的
#ifndef/#define/#endif
是。@T.C.好的。但问题基本上是一样的,它可能有一些奇怪的历史原因