【问题标题】:Why aren't my compile guards preventing multiple definition inclusions?为什么我的编译防护不能防止多个定义包含?
【发布时间】:2010-09-19 23:11:23
【问题描述】:

我有一个头文件 x.h,它包含在多个 *.c 源文件中。 这个头文件定义了一些结构变量。

我在头文件的开头放置了多重包含预防保护:

#ifndef X_H
#define X_H
...
..
//header file declarations and definitons.


#endif//X_H

在构建时,我收到与多个定义相关的链接器错误。我理解这个问题。

  1. 不会像我一样在头文件的顶部设置多重包含防护,防止头文件 xh 的多重包含,从而避免 xh 中存在的变量的多重定义吗?

  2. #pragma once 在这个特定的编译器上不起作用,那么解决方案是什么? 有人发布了this 对类似问题的回答。它似乎对我不起作用。这个解决方案是如何工作的?

【问题讨论】:

  • @Stephen:如果您已经在编辑问题标题,还请查看正文(可能还有标签,尽管不在此处)。这样可以避免重复编辑(和碰撞)。
  • @Paulo 错过了,不过一直在关注,谢谢提醒!

标签: c linker multiple-inclusions


【解决方案1】:

如果链接器抱怨,这意味着你有定义,而不仅仅是你的标题中的声明。这是一个错误的例子。

#ifndef X_H
#define X_H

int myFunc()
{
  return 42; // Wrong! definition in header.
}

int myVar; // Wrong! definition in header.

#endif

你应该像这样把它分成源文件和头文件:

标题:

#ifndef X_H
#define X_H

extern int myFunc();

extern int myVar; 

#endif

C 来源:

int myFunc()
{
  return 42; 
}

int myVar; 

【讨论】:

  • 'int myVar;'至多是一个暂定的定义;它通常不会造成麻烦。如果有一个初始化程序,它会。尽管如此,我总是使用一个明确的外部,就像你在“固定”版本中展示的那样。
  • @Jonathan:C标准中有“暂定定义”这样的东西吗?我认为发生的情况是像这样的多个定义会导致“未定义的行为”,但是在许多编译器/链接器(gcc ...)中,您得到的行为实际上就是您想要的!
  • 函数的内联声明是否可以紧跟其定义?
  • +1 表示正确differentiating between a definition and a declaration。一些相关问题的答案未能做到这一点,从而提供了技术上不正确的信息。
【解决方案2】:

标头保护仅适用于单个编译单元,即源文件。如果您碰巧多次包含一个头文件,可能是因为 main.c 包含的所有头文件又包含 stdio.h ,那么守卫会有所帮助。

如果你在x.h中定义了一个函数fmain.cutil.c所包含,那么就像在创建@时将f的定义复制粘贴到main.c中一样987654329@ 并为util.c 创建util.o。然后链接器会抱怨,尽管您有标头保护,但仍然会发生这种情况。在main.c 中有多个#include "x.h" 语句当然是可能的,因为这些守卫。

【讨论】:

  • 我有这个疑问很久了!你的解释清楚了:-)
【解决方案3】:

使用包含保护可防止一个编译单元包含两次标头。例如。如果头文件 B.h 包含 A.h 并且 B.cpp 包含 A.h 和 B.h,如果您不使用包含防护,则来自 A.h 的所有内容都将在编译 B.cpp 中声明两次。

你的包含守卫防止这种情况发生,到目前为止一切都很好。

但是你在链接时得到了多个定义,即两个编译单元定义了同一个东西,这可能意味着你在你的头文件中有一个真正的定义,对所有变量使用 extern,确保函数是内联的或在.cpp 文件。

【讨论】:

    【解决方案4】:

    如果函数不大,你可以在它们之前使用“inline”,链接器不会抱怨。

    【讨论】:

      【解决方案5】:

      使用多重包含保护可防止 编译器 错误,但您会遇到链接器错误。头文件中是否有不使用extern的数据定义?

      【讨论】:

        【解决方案6】:

        也许X_H 已经在其他地方定义了?我刚遇到这个问题,Xlib 在 /usr/include/X11/X.h 中定义了X_H

        要检查,您可以致电gcc -dM -E(如果您使用的是 gcc),例如在我使用的构建系统中,它与CC=gcc CFLAGS="-dM -E" make 一起工作。如果输出文件包含#define X_H,即使您从文件中删除它(例如使用Y_H),那么它已经在您的源代码之外定义。

        【讨论】:

        • 如果已经定义了包含守卫,他会得到一个关于没有定义的错误,而不是多个定义,对吧?
        猜你喜欢
        • 2013-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-01
        • 1970-01-01
        • 2020-01-17
        • 1970-01-01
        相关资源
        最近更新 更多