为啥我的编译防护不能防止多个定义包含?
Posted
技术标签:
【中文标题】为啥我的编译防护不能防止多个定义包含?【英文标题】:Why aren't my compile guards preventing multiple definition inclusions?为什么我的编译防护不能防止多个定义包含? 【发布时间】:2008-10-30 09:52:40 【问题描述】:我有一个头文件 x.h,它包含在多个 *.c 源文件中。 这个头文件定义了一些结构变量。
我在头文件的开头放置了多重包含预防保护:
#ifndef X_H
#define X_H
...
..
//header file declarations and definitons.
#endif//X_H
在构建时,我收到与多个定义相关的链接器错误。我理解这个问题。
不会像我一样在头文件顶部设置多重包含防护,防止头文件 x.h 的多重包含,从而避免 x.h 中存在的变量的多个定义?
#pragma
once 在这个特定的编译器上不起作用,那么解决方案是什么?
有人发布了this 对类似问题的回答。它似乎对我不起作用。这个解决方案是如何工作的?
【问题讨论】:
@Stephen:如果您已经在编辑问题标题,还请查看正文(可能还有标签,尽管不在此处)。这样可以避免重复编辑(和碰撞)。 @Paulo 错过了,不过一直在关注,谢谢提醒! 【参考方案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
中有函数f
的定义被main.c
和util.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
),那么它已经在您的源代码之外定义。
【讨论】:
如果已经定义了包含守卫,他会得到一个关于没有定义的错误,而不是多个定义,对吧?以上是关于为啥我的编译防护不能防止多个定义包含?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的 React 应用程序不能使用我的 Apache .htaccess 文件来防止 404?