需要澄清 #ifndef #define

Need clarification on #ifndef #define

本文关键字:#ifndef #define      更新时间:2023-10-16

我正在处理的代码有多个标头和源文件,用于不同的类face.cc, face.hh, cell.cc, cell.hh edge.cc edge.hh,标头包含如下内容,

#ifndef cellINCLUDED
#define cellINCLUDED
#ifndef faceINCLUDED
#define faceINCLUDED

我看穿了 http://www.cplusplus.com/forum/articles/10627/,看到了包括警卫在内的写作方式是

#ifndef __MYCLASS_H_INCLUDED__
#define __MYCLASS_H_INCLUDED__

因此,在我正在处理的上述代码中,编译器是否自动理解它正在寻找face.hhcell.hh文件?

更好的问题:写作__CELL_H_INCLUDED__cellINCLUDED一样吗?

#ifndef __MYCLASS_H_INCLUDED__
#define __MYCLASS_H_INCLUDED__

所以在我正在处理的上面的代码中,编译器会自动 知道它正在寻找 face.hh 或 cell.hh 文件吗?

不,编译器不会自动理解您的意思。

真正发生的情况是,在编译翻译单元时,编译器会保存全局定义的宏列表。因此,您正在做的是定义宏__MYCLASS_H_INCLUDED__(如果它尚不存在)。

如果定义了该宏,则实际编译器将不会分析该#ifndef直到#endif。因此,您可以测试该宏是否存在,以确定编译器是否已解析该头文件以将其包含在翻译单元中一次且仅包含一次......这是因为编译器将每个翻译单元编译为一个平展文件(合并所有#includes之后)

见 https://en.wikipedia.org/wiki/Include_guard

写作__CELL_H_INCLUDED__cellINCLUDED一样吗?

是的,它是。。。。有些人更喜欢使用带下划线前缀和后缀的宏作为包含保护的原因是因为它们被用作标识符的可能性极低......但同样,下划线可能会与编译器发生冲突......

我更喜欢这样的东西:CELL_H_INCLUDED

如果您使用 cellINCLUDED ,则有可能有一天,有人可能会将其用作该翻译单元中的标识符

预处理器定义没有特殊含义。唯一的要求是它们在模块中保持唯一,这就是为什么文件名通常是它们的一部分。

特别是,防止双重包含的机制不是"嵌入"语言的,而是简单地使用预处理器的机制。

话虽如此,现在每个值得关注的编译器都支持#pragma once,你可能会解决这个问题。

正如您引用的链接所说,"编译器没有自己的大脑" - 所以要回答您的问题,不,编译不了解涉及哪些特定文件。它甚至不会理解"__cellINCLUDED"在概念上与特定文件有任何关系。

相反,包含保护只是防止多次包含其打开 #ifndef 和关闭 #endif 之间的逻辑。作为程序员,告诉编译器不要多次包含该代码 - 编译器本身并没有做任何"智能"的事情。

不,这本质上是在告诉编译器/解析器,如果这已经放入程序中,请不要已经加载。

这应该位于 .h 文件的顶部(底部有一个 #endif)。

假设你有mainProgram.cpp和Tools.cpp,每个文件都加载fileReader.h。当编译器编译每个 cpp 文件时,它将尝试加载 fileReader.h。除非你告诉它不要这样做,否则它将加载所有文件读取器文件两次。

ifndef = 如果未定义

所以当你使用这些(以及 .h 文件中的所有代码之后的 #endif)你是说:

if not defined: cellINCLUDED
then define: cellINCLUDED with the following code:
[code]
end of code

因此,当它第二次加载 .h 文件中的代码时,它会命中 If 未定义的位并在第二次忽略代码。

这减少了编译时间,也意味着如果您使用的是糟糕/旧的编译器,它不会尝试再次将代码塞进去。