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

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.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),那么它已经在您的源代码之外定义。

【讨论】:

如果已经定义了包含守卫,他会得到一个关于没有定义的错误,而不是多个定义,对吧?

以上是关于为啥我的编译防护不能防止多个定义包含?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 React 应用程序不能使用我的 Apache .htaccess 文件来防止 404?

犯错误:多个定义...尽管包括警卫

#ifndef#define#endif防止头文件重复包含

如何做好网站安全防护 防止网站被黑?

当组件中有解构赋值时,为啥默认道具不能防止 TypeError?

为啥 referentialIntegrity = "prisma" 不能防止迁移中的外键?