【问题标题】:Confusion with Preprocessor Directives与预处理器指令混淆
【发布时间】:2018-01-23 12:21:21
【问题描述】:

我有三个文件

文件“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”第二次,#ifndef 测试返回 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中

【问题讨论】:

  • 它没有价值。它只是为了确保类型和函数定义只被编译器评估一次而定义。
  • @Jean-FrançoisFabre 你的意思是宏 GRANDPARENT_H 是空的
  • 只需运行gcc -E 以在预处理器完成其工作后获取代码,如果不是 gcc,请检查您正在使用的编译器的文档。 Clang 使用了相同的 -E 标志(clang.llvm.org/docs/CommandGuide/clang.html
  • @rimiro 你可以写#define FOO 123。然后定义了预处理器符号FOO,每次写FOOFOO都会被123替换。但你也可以写#define FOO。然后预处理符号FOO也被定义了,每次你写FOO时,FOO都会被替换成一个空字符串。
  • 宏的内容只是它所在行之外的内容,而不是文件内容。

标签: c macros c-preprocessor ifndef


【解决方案1】:

如果你手动“扩展”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;
};

就是这样!

【讨论】:

  • 所以当我们写#define GRANDPARENT_H时,我们定义了一个空宏,它与它下面的行无关??请回答这是让我感到困惑的最后一件事
  • @rimiro 是的,就是这样。
猜你喜欢
  • 1970-01-01
  • 2012-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-24
相关资源
最近更新 更多