与预处理器指令混淆

时间:2018-01-23 12:21:22

标签: c macros c-preprocessor ifndef

我有三个文件

档案“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"

维基说

  

这里,第一次包含“grandparent.h”会导致宏   要定义GRANDPARENT_H。然后,当“child.c”包括时   “grandparent.h”第二次,#ifnf测试返回false,并且   预处理器向下跳到#endif,从而避免了第二个   struct foo的定义。该程序编译正确。

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中。

1 个答案:

答案 0 :(得分:3)

如果您手动“展开”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宏。它是空的,但这并不重要,重要的是它是定义的

然后,代码定义了你的结构......

当预处理器遇到第二个#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;
};

就是这样!