我在我的c ++项目中的每个头文件中使用#pragma once(或者你使用includeguardsàla #ifndef...).这是巧合还是你在大多数开源项目中找到的东西(避免只依赖于个人项目经验的答案).如果是这样,为什么不相反:如果我想要多次包含头文件,我使用一些特殊的预处理器命令,如果不是,我将文件保留原样.
C++编译器的行为是根据它如何处理每个转换单元来指定的.翻译单元是预处理器在其上运行后的单个文件.事实上,我们有一个在某些文件中收集声明并将它们称为"头"文件的约定,这对编译器或C++标准来说毫无意义.
简单地说,标准没有提供"头文件",所以它不能提供自动包含防护头文件.该标准仅提供预处理器指令#include,其余仅仅是约定.没有什么可以阻止你向前声明所有内容并且不使用头文件(除了怜悯任何人应该维护该代码......).
因此头文件并不特别,并且没有办法说"这是一个头文件,守护它",但为什么我们不能保护所有得到#include的东西?因为#include它比其他语言的模块系统更强大.#include导致预处理器粘贴到其他文件中,不一定是头文件.有时,如果在不同文件中的一堆不同命名空间中使用相同的using和typedef声明,这可能很方便.您可以将它们收集在一个文件中,#include并在几个地方收集它们.你不希望自动包含警卫阻止你这样做.
使用#ifndef和#define有条件地包括标题也仅仅是惯例.该标准没有"包括警卫"的概念.(然而现代编译器实际上都知道包括警卫.识别包含警卫可以允许更快的编译,但它与正确实施标准无关.)
变得迂腐
该标准确实使用了"header"这个词,特别是在参考C和C++标准库时.但是,行为#include是在§ 16.2 *Source file* inclusion(emph.mine)下定义的,并且它不会向头文件授予任何特殊权限.
努力将适当的模块系统纳入C++标准.
因为歇斯底里的葡萄干.
C++预处理器几乎与40多年前设计的C预处理器完全相同.当时的编译器要简单得多.预处理器甚至更简单,只是一个愚蠢的宏处理器甚至不是编译器.尽管C++标准没有规定标准头文件的工作方式,但概念#include上仍然与40多年前相同:它使预处理器将命名文件的内容插入到包含文件中.
在一个简单的20世纪70年代C代码库中,没有很多相互依赖关系和子模块,可能不需要包含保护.早期的预标准C没有使用函数原型,这是目前大多数包含文件的用法.如果包含两次标题导致错误,您可能会重新安排代码以防止它被包含两次.
随着代码库的增长和变得越来越复杂,我认为偶然包括一个标题两次(可能间接地,通过其他标题)的问题变得更加普遍.一种解决方案可能是改变预处理器以使其更智能,但这需要每个人都使用新的预处理器,并且会使它变得越来越大.因此,开发了一个使用预处理器(#define和#ifndef)的现有功能来解决问题的约定,而不是通过防止头部被包括两次,而是简单地使头部包括两次无害,因为它在第一次之后没有效果已经包括了.
随着时间的推移,约定变得更加广泛使用,现在几乎是通用的,除了标题的罕见示例,其被设计为包括两次并且被编写为以这种方式正确地工作(例如<assert.h>).
后来仍然#pragma once被一些编译器引入作为替代,不可移植的方式与包含警卫具有相同的效果,但到那时,有几千个各种C预处理器的副本正在使用围绕这个词包括警卫已经成为常态.
因此,目前的行为几乎肯定是由于历史原因.今天编写的现代语言,对于今天功能非常强大的计算机,如果从头开始设计,就不会使用类似C预处理器的东西.但C并不是在21世纪设计的.我认为包含守卫协议是随着时间的推移缓慢建立的,并且不需要对现有软件进行任何更改以使其工作.现在更改它会破坏依赖于当前行为的未知数量的C和C++代码,并且可能不是一个选项,因为向后兼容性对于C和C++都很重要.
| 归档时间: |
|
| 查看次数: |
1271 次 |
| 最近记录: |