为啥编译器默认不自动添加或生成包含保护?

Posted

技术标签:

【中文标题】为啥编译器默认不自动添加或生成包含保护?【英文标题】:Why doesn't the compiler automatically add or generate an include guard by default?为什么编译器默认不自动添加或生成包含保护? 【发布时间】:2015-08-10 04:33:36 【问题描述】:

我知道 C 或 C++ 代码通常需要像这样使用包含保护:

#ifndef __A__H__
#define __A__H__
class A
;
#endif

为了加快编译时间,在其他cpp(例如:B.cpp)中,它可以改变

#include "A.h"

到:

#ifndef __A__H__
#include "A.h"
#endif

但问题是为什么编译器不自动添加或生成包含保护,因此如果通常需要包含保护,程序员为什么需要手动添加它?

【问题讨论】:

它不需要它,它只是在某些情况下很方便。但它没有自动生成的主要原因是因为它不是这样做的语言标准的一部分。 因为有时多次包含同一个标题很有用。 我想在这里扮演魔鬼的代言人,假设编译器需要能够自动生成守卫,可以吗?它甚至可行吗?我在想,编译器如何确定文件已经包含在内?如果您在不同的绝对路径中有 2 个同名文件,但它们实际上是同一个文件,该怎么办? 顺便说一句,您不能使用以下划线开头的标识符 Including header files in C/C++ more than once 的可能重复项 【参考方案1】:

有时生成标头保护是绝对不正确的。标准包含一个示例:C 中的 <assert.h> 和 C++ 中的 <cassert>

重新包含这些标头的效果取决于(重新)包含标头时 NDEBUG 宏的状态。写是合法的:

#undef NDEBUG
#include <assert.h>
…code using assert…
#define NDEBUG 1
#include <assert.h>
…more code using assert…

如果编译器自动生成标头保护,那将无法正常工作。因此,编译器不会自动生成标头保护。


顺便说一句,用户代码不应使用以双下划线或下划线大写字母开头的标头保护宏名称。这些名称是为实现而保留的。在 C++ 中,任何用户定义的名称都不能合法地包含双下划线。使用类似的东西:

#ifndef A_H_INCLUDED
#define A_H_INCLUDED
…body of header…
#endif

【讨论】:

【参考方案2】:

编译器,或更严格的预处理器无法确定程序员使用包含的意图。编译器没有明确区分 .h 文件和 .c 或 .cpp 文件;它们仅在其中一处的代码类型上有所不同。事实上,编译器只处理一个翻译单元; C 预处理器负责将所有包含的文件连接到一个文件中进行编译。预处理器忽略它之前包含的包含是不正确的,因为它没有代码的语义知识,并且可能会通过事后猜测开发人员而导致预期行为发生变化。

在某些情况下,IDE 可能会为其生成的模板代码添加包含保护。例如,Microsoft Visual Studio 将为通过其项目启动向导生成的代码添加它们。如果发生这种情况,这完全是 IDE 的责任,而不是编译器或预处理器的责任。

【讨论】:

以上是关于为啥编译器默认不自动添加或生成包含保护?的主要内容,如果未能解决你的问题,请参考以下文章

为啥当类包含任何参数化构造函数时编译器不提供默认构造函数? [复制]

C++编译器自动生成的堆栈保护检查

C++编译器自动生成的堆栈保护检查

保护生成的源文件

为啥 emscripten 不编译我的函数?

编译知识