你如何实现头文件保护,并且在它们之间可以放置什么内容?

39
LearnCpp.com | 1.10 — 预处理器的首次接触中。在头文件保护下,有以下代码片段:

add.h:

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

subtract.h:

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

main.cpp:

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

在实施头文件保护时,如下所述:
#ifndef ADD_H
#define ADD_H

// your declarations here

#endif
  • 这里的声明应该是什么?而且,int main() 应该放在 #endif 之后吗?
  • 添加 _H 是一种约定还是必须要做的事情?

那么,头文件保护是否已经在“add.h”中实现? - Simplicity
我想出了一种更好的保护方式,用于两个类之间存在交叉引用时,避免手动放置前向声明。解决方案在这里: https://dev59.com/4msz5IYBdhLWcg3wQFe2#56497150 - angarciaba
5个回答

72

FILENAME_H是一种约定。如果你真的想的话,你可以使用#ifndef FLUFFY_KITTENS作为头文件保护(前提是它没有在其他地方定义),但如果你在其他地方定义了它,比如用于某些事情的小猫数量,那就会成为一个棘手的Bug。

在头文件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 文件都只能包含被保护的头文件一次


1
所以,你上面写的命令应该只放在.h文件中,对吗?谢谢。 - Simplicity
但是,在main.cpp中,#include "mymath.h"不会被包含两次吗?谢谢。 - Simplicity
这正是为什么要使用头文件保护的原因。(mymath.h 应该有它自己的 #ifndef MYMATH_H #def MYMATH_H #endif - Anže

19
  • 一个实现文件(".cpp")的预处理结果是一个翻译单元(TU)。

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

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

  • 头文件防卫解决的问题是当给定的头文件在同一TU中被包含多次时,防止多重定义错误。

  • 头文件防卫的工作原理是通过“包装”头文件的内容,使第二次及以后的包含成为无操作。#ifndef / #define指令应该是文件的前两行,而#endif应该是最后一行。

  • 头文件防卫仅用于头文件。不要在头文件中定义主函数:将其放在实现文件中。

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

#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和其他地方可以找到几种不同的包含保护命名风格;此答案提供了良好的标准和概述。


谢谢您的回复。我们如何避免在 main.cpp 中出现两次 #include "mymath.h"?谢谢。 - Simplicity
1
@SWEngineer:你不需要这样做;include guard 会使得除了第一次之外的每次头文件引用都不起作用。 - Fred Nurk

3

所有的头文件保护只是为了确保你的头文件只被包含一次。(如果它们被多次包含,它们将被忽略。)

你使用的名称并不重要,但惯例上使用大写的文件名,包括扩展名,就像你演示的那样。

你的main应该放在一个.cpp文件中,但如果你把它放在头文件中,请将其放在保护内,以免被多次声明。


谢谢您的回复。但是,问题不是出在“mymath.h”上吗?因为我们在“main.cpp”中有两个包含到“add.h”和“subtract.h”的头文件。 - Simplicity
是的,确实如此。这就是为什么你应该在那里放置一个 MATH_H 保护的原因。(我不确定我是否正确理解了你的问题...) - user541686
“in there” 指的是哪里?你是指 mymath.h 吗? - Simplicity

1
不,int main() 函数应该放在 .cpp 文件中。声明应该放在你原本打算放在头文件中的其他内容里。_H 是一种约定俗成的写法,你可以看到各种不同的头文件保护约定。

1

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

_H仅用于指示某人将使用包含保护来包含头文件。

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


gcc 也可以处理 #pragma once。 - kinnou02

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接