为什么我的编译保护不能防止多个定义包含?

时间:2008-10-30 09:52:41

标签: c linker multiple-inclusions

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

我在头文件的开头添加了多个包含防护措施:

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


#endif//X_H

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

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

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

6 个答案:

答案 0 :(得分:49)

如果链接器抱怨,则表示您的标题中有定义而不仅仅是声明。这是一个错误的例子。

#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; 

答案 1 :(得分:12)

使用include guard可防止一个编译单元包含两次头文件。例如。如果标题B.h包括A.h而B.cpp包括A.h和B.h,那么如果你没有使用包含保护,那么A.h中的所有内容都将在编译B.cpp中被声明两次。

你的包含警卫可以防止这种情况发生,一切都很好。直到现在。

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

答案 2 :(得分:12)

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

如果您在fx.h中包含main.c中的函数util.c的定义,则就像复制和粘贴{f的定义一样在创建main.c时为main.o创建util.c并为util.o创建#include "x.h"以创建main.c。然后链接器会抱怨,尽管你的标题守卫发生了这种情况。当然,由于这些警卫,{{1}}中有多个{{1}}语句是可能的。

答案 3 :(得分:6)

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

答案 4 :(得分:2)

使用多包含保护会阻止编译器错误,但是您收到链接器错误。您是否在头文件中有不使用extern

的数据定义

答案 5 :(得分:0)

也许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),那么它已在源代码之外定义。