与预处理器指令混淆

Confusion with Preprocessor Directives

我有三个文件

文件"grandparent.h"

#ifndef GRANDPARENT_H
#define GRANDPARENT_H

struct foo {
    int member;
};

#endif /* GRANDPARENT_H */

文件"parent.h"

#include "grandparent.h"

文件"child.c"

 #include "grandparent.h"
 #include "parent.h"

维基说

Here, the first inclusion of "grandparent.h" causes the macro GRANDPARENT_H to be defined. Then, when "child.c" includes "grandparent.h" the second time, the #ifndef test returns false, and the preprocessor skips down to the #endif, thus avoiding the second definition of struct foo. The program compiles correctly.

q1。 “第一个包含 "grandparent.h" 会导致 GRANDPARENT_H 待定义",所以我的理解基本上是 定义一个名为 GRANDPARENT_H 的宏,但我不知道理解的是该宏的内容(即 GRANDPARENT_H)将如何包含在 child.c.

我们只是在定义宏GRANDPARENT_H 即

#define GRANDPARENT_H

struct foo {
    int member;
};

但是它的内容会怎样

struct foo {
    int member;
};

被列入child.c

如果你手动 "expand" child.c 直到没有 #include 剩余:

//grandparent.h

#ifndef GRANDPARENT_H    // <- not defined at this point
#define GRANDPARENT_H    // <- now it's defined

struct foo {
    int member;
};

#endif /* GRANDPARENT_H */
//parent.h

//#include "grandparent.h" resolves into
//grandparent.h

#ifndef GRANDPARENT_H   // <- already defined, skip until matching #endif
#define GRANDPARENT_H   // <- not executed by preprocessor

struct foo {            // <- not provided to the compiler
    int member;
};

#endif /* GRANDPARENT_H */

现在依次阅读。 第一行检查是否定义了宏GRANDPARENT_H。显然不是,因为它是代码的第一条指令。

第二行定义了GRANDPARENT_H宏。它是空的,但这并不重要,重要的是它是 defined.

然后,代码定义您的结构...

当预处理器遇到第二个 #ifdef GRANDPARENT_H 时,宏已经定义,因此它会跳过文件的全部内容,您不会得到任何 foo redefined 错误。

通过使用 -E 选项查看预处理的 child.c 文件来确认:

$ gcc -E child.c
# 1 "child.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "child.c"
# 1 "grandparent.h" 1


struct foo {
    int member;
};
# 2 "child.c" 2
# 1 "parent.h" 1
# 2 "child.c" 2

如您所见,该结构仅定义一次。

请注意,大多数编译器现在支持更简单的方法来执行此操作:只需插入

#pragma once

在文件的开头。像这样:

#pragma once

struct foo {
    int member;
};

就是这样!