【问题标题】:Header guards in C++ and CC++ 和 C 中的标头保护
【发布时间】:2011-06-13 14:47:35
【问题描述】:

LearnCpp.com | 1.10 — A first look at the preprocessor。在Header guards下,有那些代码sn-ps:

添加.h:

#include "mymath.h"
int add(int x, int y);

减去.h:

#include "mymath.h"
int subtract(int x, int y);

main.cpp:

#include "add.h"
#include "subtract.h"

在实现header guard时,提到如下:

#ifndef ADD_H
#define ADD_H

// your declarations here

#endif
  • 这里有什么声明?而且,int main() 应该在 #endif 之后吗?
  • 添加_H 是惯例还是必须做的事情?

谢谢。

【问题讨论】:

  • 那么,上面实现的标头gurad是否插入到“add.h”中?
  • 我想出了一个更好的保护,当两个类之间存在交叉引用时,避免手动放置前向声明。解决方案在这里:stackoverflow.com/a/56497150/6184124

标签: c++ c macros header-files include-guards


【解决方案1】:

FILENAME_H 是一个约定。如果你真的想要,你可以使用#ifndef FLUFFY_KITTENS 作为标题保护(前提是它没有在其他任何地方定义),但如果你在其他地方定义它,这将是一个棘手的错误,比如小猫的数量。

在头文件 add.h 中,声明实际上介于 #ifndef#endif 之间。

#ifndef ADD_H
#define ADD_H

#include "mymath.h"
int add(int x, int y);

#endif

最后,int main() 不应该在头文件中。它应该始终位于.cpp 文件中。

清除它:

#ifndef ADD_H 基本上意味着“如果 ADD_H 在文件或包含的文件中不是 #defined,则编译 #ifndef#endif 指令之间的代码”。因此,如果您在.cpp 文件中多次尝试#include "add.h",编译器将看到ADD_H 已经是#defined,并将忽略#ifndef#endif 之间的代码。标头保护仅防止标头文件多次包含在同一个.cpp 文件中。标头保护不会阻止其他 .cpp 文件包含头文件。但是所有.cpp 文件都可以包含受保护的头文件只能包含一次

【讨论】:

  • 那么,你上面写的命令应该只放在 .h 文件中吗?谢谢。
  • 但是,#include "mymath.h" 不会在 main.cpp 中包含两次吗?谢谢。
  • 这正是使用头部保护的原因。 (mymath.h 应该有它自己的 #ifndef MYMATH_H #def MYMATH_H #endif
【解决方案2】:
  • 预处理一个实现(“.cpp”)文件的结果是一个翻译单元(TU)。

  • 标头可以包含其他标头,因此一个标头可能会在同一个 TU 中间接包含多次。 (你的 mymath.h 就是一个例子。)

  • 每个 TU 最多只能出现一次定义。 (有些定义也不能在多个 TU 中;这种情况略有不同,这里不讨论。)

  • 包含守卫解决的问题是防止在一个 TU 中多次包含给定标头时出现多个定义错误。

  • 包含保护通过“包装”标头的内容来工作,使得第二个和后续包含是无操作的。 #ifndef/#define 指令应该是文件的前两行,#endif 应该是最后一行。

  • 包含保护仅用于标头。不要在头文件中定义你的 main 函数:把它放在一个实现文件中。

如果你有一个将定义一个类型并声明一个函数的头文件,但也需要一个头文件本身:

#include "other_header.h"

struct Example {};

void f();

用包含守卫“包装”它会给出文件的完整内容:

#ifndef UNIQUE_NAME_HERE
#define UNIQUE_NAME_HERE

#include "other_header.h"

struct Example {};

void f();

#endif

用于包含保护的名称必须是唯一的,否则冲突的名称会产生令人困惑的结果。这些名称只是简单的宏,语言中没有任何东西强制执行某种样式。但是,项目约定通常会提出要求。您可以在 SO 和其他地方找到几种不同的包含守卫命名样式; this answer 提供了良好的标准和良好的概述。

【讨论】:

  • 感谢您的回复。我们如何避免 #include "mymath.h" 在 main.cpp 中出现两次?谢谢。
  • @SWEngineer:你没有;包含守卫使标头的每个包含,在第一个之后,什么都不做。
【解决方案3】:

所有标头守卫所做的就是只允许您的标头包含一次。 (如果它们被包含多次,则会被忽略。)

您使用的名称无关紧要,但习惯上使用大写的文件名,包括您演示的扩展名。

您的main 确实应该在.cpp 文件中,但如果您将它放在标题中,请将它放在守卫内,这样它就不会被多次声明。

【讨论】:

  • 感谢您的回复。但是,问题不在于“mymath.h”并在“main.cpp”中包含两次,因为我们有两个包含到“add.h”和“subtract.h”?
  • 是的,确实如此。这就是为什么你应该在那里放置一个MATH_H 警卫。 (我不确定我是否正确理解了你的问题......)
  • 你所说的“在那里”是什么意思?你是说 mymath.h 吗?
【解决方案4】:

不,int main() 放在 .cpp 中。声明是您要放在标题中的其他内容。 _H 是一个约定,你可以在周围看到各种 header 保护约定。

【讨论】:

    【解决方案5】:

    我在头文件和定义中声明了一个声明,或者int main() 出现在source.cpp 文件中。

    _H 只是表示有人将使用包含保护来包含头文件。

    如果您使用的是 MSVC++,也可以使用 #pragma once

    【讨论】:

    • gcc 也可以处理一次#pragma
    猜你喜欢
    • 2020-04-30
    • 1970-01-01
    • 2013-11-17
    • 2013-11-13
    • 2016-01-05
    • 2015-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多