C++ 避免双重包含:预处理器指令与makefile

C++ 避免双重包含:预处理器指令与makefile,c++,makefile,c-preprocessor,multiple-inclusions,C++,Makefile,C Preprocessor,Multiple Inclusions,我正在努力从《科学怪人》和《一个文件》的数千行程序转变为结构良好、组织有序的多文件程序。现在看起来很自然(天真)的事情是为我的三个文件制作一个包含标题的三角恋: 文件1包括文件2、文件4 文件2包括文件3、文件4 文件3包括文件1。。。。等 这些文件包含我在其他文件之间需要的变量、方法、结构等 当然,我得到了双重包含错误 我的问题:我应该通过在头文件中使用预处理器指令(例如,完全在头文件中包含结构、方法等)来避免这些问题,还是应该使用makefile进行编译(我听说makefile也可以用来解决

我正在努力从《科学怪人》和《一个文件》的数千行程序转变为结构良好、组织有序的多文件程序。现在看起来很自然(天真)的事情是为我的三个文件制作一个包含标题的三角恋:
文件1包括文件2、文件4
文件2包括文件3、文件4
文件3包括文件1。。。。等
这些文件包含我在其他文件之间需要的变量、方法、结构等

当然,我得到了双重包含错误

我的问题:我应该通过在头文件中使用预处理器指令(例如,完全在头文件中包含结构、方法等)来避免这些问题,还是应该使用makefile进行编译(我听说makefile也可以用来解决此问题,但我从未制作过)?

您应该始终使用,以便在需要时可以包含通用头文件。这实际上独立于Makefile或您选择使用的任何构建工具


如果可能的话,您还应该尝试避免循环依赖,否则您将需要使用来解决它们。

预处理器指令和包含声明和共享结构等的头是解决方法。Makefiles只是帮助编译源代码并将对象文件链接到外部库以形成最终二进制文件,它无助于解决多重包含问题。 简而言之,在头文件中声明以下内容:

  • 结构
  • 作为extern共享变量(并在一个.c文件中定义)
  • 方法声明(并在一个.c文件中定义方法)

使用
#IFNDEF
#ENDIF
保护它们,然后将头文件包含到各种.c文件中…

下面是“inv_tree.h”的包含保护的示例

#ifndef INV_TREE_H
#define INV_TREE_H
...
#endif
通过将“inv_tree.h”的内容与警卫包围起来,它会检查在包含“inv_tree.h”之前是否定义了inv_tree.h。如果没有定义,它会定义它并包含“inv_tree.h”,否则它不包含头文件 头文件应仅包括绝对必要的头文件。这意味着如果从类派生或显式使用类作为成员,则从另一个头文件派生

如果您只使用指向类的引用或指针,那么只需向前声明它(不包括heder文件)

通过这种方式,您可以中断循环头包含


注意:您应该始终使用头保护,因为头可能通过多个路径包含,而这些路径对于头文件的用户来说并不明显。

使用前向声明中断循环SNO。您使用前向声明来打破循环。@马丁·约克:“循环依赖”和“循环”有什么区别?我认为它们是同义词,“循环依赖”是一个不太含糊的术语。好的,如果添加的话,包括对所有相关的头文件的保护,并确保需要它们的每个文件都包含它们。但是现在我得到了编译错误(通过分别编译文件来解决,例如g++-c included.cc、g++-c Program.cc、g++-o Program.o included.o未定义的符号:“initOutFile(u sFILE*&,char const*,char const*,char const*),引用自:cccHyQZI中的initialize(char*)。o ld:symbol(s)找不到集合2:ld返回1退出状态这是链接器错误:编译成功,但它发出了链接器在任何地方都找不到的符号。是否在编译器命令行中指定了所有.cc文件?否我没有…:(--成功了,谢谢你的帮助sjr!像这样简单的防护只对玩具项目有用。学习生成GUID或使用保证唯一的防护(包括公司/项目/命名空间信息)关于共享变量:如果我在头文件中声明某个变量,并希望在许多其他文件中使用它,为什么要将其声明为“extern”?到目前为止,我只将其声明为const,并包含头文件…预处理器完全将文件(例如.h)的内容替换到执行include(.c文件)的文件中,然后编译器在最后一个文件上执行它的操作。如果你只是在头文件中声明它,并将它包含在多个.c文件中,那么最终每个编译的.o文件都有自己的变量副本,这不会使它共享。如果你说的是常量,那么当然,不声明extern应该可以。顺便说一句,我需要再次验证这一点,哈有一阵子没碰C了。。。