我有一个头文件x.h,它包含多个* .c源文件。 此头文件定义了一些结构变量。
我在头文件的开头添加了多个包含防护措施:
#ifndef X_H
#define X_H
...
..
//header file declarations and definitons.
#endif//X_H
在构建时,我得到与多个定义相关的链接器错误。我理解这个问题。
不会像我一样在头文件顶部放置多重包含防护,防止头文件xh的多个包含,从而避免xh中存在的变量的多个定义?
#pragma
一旦对这个特定的编译器不起作用,那么解决方案是什么?
有人发表了this对类似问题的回答。它似乎对我不起作用。该解决方案如何运作?
答案 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
,那么警卫会有所帮助。
如果您在f
和x.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
),那么它已在源代码之外定义。