27

我最近对​​C和编译过程 的基本知识已经生疏了。我试图找出以下问题的答案,但无法连接编译、链接和预处理阶段的基础知识。在谷歌上快速搜索也没有多大帮助。所以,我决定来到知识的终极来源:)

我知道:不应该在 .h 文件中定义变量。可以在那里声明它们。

原因:因为头文件可能会从多个位置包含在内,因此多次重新定义变量(链接器给出错误)。

可能的解决方法:在头文件中使用 header-guards 并在其中定义变量。

这真的是一个解决方案吗:不。因为标头保护用于预处理阶段。就是告诉编译器这部分已经包含了,不要再包含了。但是我们的多重定义错误出现在链接器部分——在编译之后。

这整件事让我对预处理和链接的工作方式感到困惑。我认为如果已定义标头保护符号,预处理将不包含代码。在那种情况下,不应该解决变量问题的多重定义吗?

这些预处理指令使编译过程免于在标头保护下重新定义符号,但链接器仍然获得符号的多个定义,会发生什么?

4

4 回答 4

29

我过去使用过的一件事(当全局变量流行时):

var.h 文件:

...
#ifdef DEFINE_GLOBALS
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN int global1;
EXTERN int global2;
...

然后在一个.c 文件中(通常是包含 main() 的文件):

#define DEFINE_GLOBALS
#include "var.h"

其余的源文件通常只包含“var.h”。

请注意, DEFINE_GLOBALS 不是标头保护,而是允许根据是否定义变量来声明/定义变量。此技术允许声明/定义的一份副本。

于 2010-02-07T12:50:06.457 回答
27

标头保护保护您免受单个源文件中的多个包含,而不是多个源文件。我猜你的问题源于不理解这个概念。

并不是说预处理器守卫在编译期间从这个问题中节省了。实际上在编译期间,只有一个源文件被编译成一个 obj,符号定义没有被解析。但是,在链接器尝试解析符号定义时进行链接的情况下,看到多个定义导致它标记错误时会感到困惑。

于 2010-02-07T13:05:30.010 回答
10

您有两个 .c 文件。它们分别编译。每一个都包含你的头文件。一次。每个人都有一个定义。它们在链接时发生冲突。

常规的解决方案是:

#ifdef DEFINE_SOMETHING
int something = 0;
#endif

然后你只在一个.c 文件中#define DEFINE_SOMETHING 。

于 2010-02-07T12:48:37.980 回答
8

标头保护阻止标头文件多次包含在同一个翻译单元中(即在同一个 .c 源文件中)。如果您将文件包含在两个或更多翻译单元中,它们将不起作用。

于 2010-02-07T12:51:58.430 回答