【问题标题】:Avoiding double inclusion: Preprocessor directive vs. makefiles避免双重包含:预处理器指令与生成文件
【发布时间】:2011-06-27 09:50:28
【问题描述】:

我正在努力从 frankenstein 和一个文件的数千行程序转变为结构良好且组织良好的多文件程序。现在似乎很自然(天真)的是为我的三个文件制作一个包含标题的三角:
file_1 包括 file_2、file_4
file_2 包括 file_3、file_4
file_3 包括 file_1 .... 等等
这些文件有我在其他文件之间需要的变量、方法、结构等。

当然,我会遇到双重包含错误。

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

【问题讨论】:

  • 使用前向声明打破循环

标签: c++ makefile c-preprocessor multiple-inclusions


【解决方案1】:

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

如果可能,您还应该尽量避免循环依赖,否则您将需要使用forward declarations 来解决它们。

【讨论】:

  • 没有。您使用前向声明来打破循环。
  • @Martin York:“循环依赖”和“循环”有什么区别?我认为它们是同义词,“循环依赖”是不太含糊的术语。
  • 好的,所以如果将包含保护添加到所有相关的头文件中,并确保每个需要它们的文件都包含它们......但是现在我遇到了编译错误(通过分别编译文件,即 g++ -c included.cc, g++ -c Program.cc, g++ -o Program Program.o included.o 未定义符号:"initOutFile(__sFILE*&, char const*, char const*, char const *)",引用自:cccHyQZI.o 中的初始化(char*) ld:未找到符号 collect2:ld 返回 1 个退出状态
  • 这是一个链接器错误:编译成功但它发出了链接器无法在任何地方找到的符号。您是否在编译器命令行中指定了所有 .cc 文件?
  • 不,我没有... :( ---得到它的工作,感谢您的帮助 sjr!
【解决方案2】:

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

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

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

【讨论】:

  • 关于共享变量:如果我在头文件中声明了某个变量,并且想在许多其他文件中使用它,为什么要将其声明为“extern”?到目前为止,我只是将其声明为 const,并包含标题...
  • 预处理器将文件(比如.h)的内容完全替换到执行包含(.c 文件)的文件中,然后编译器在最终文件上执行它的操作。如果您只是在标头中声明它并将其包含在多个 .c 文件中,您最终将让每个编译的 .o 文件都有自己的变量副本,而不会使其共享。如果你在谈论一个常量,那么当然,不声明 extern 应该没问题。顺便说一句,我需要再次验证这一点,有一段时间没有接触 C...
【解决方案3】:

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

#ifndef INV_TREE_H
#define INV_TREE_H
...
#endif

通过将“inv_tree.h”的内容与守卫包围起来,它会检查天气 INV_TREE_H 在包含“inv_tree.h”之前是否已定义,如果未定义,则定义它并包含“inv_tree.h”,否则不包含它

【讨论】:

  • 像这样简单的守卫只对玩具项目有用。学习生成 guid 或使用保证唯一的守卫(包括公司/项目/命名空间信息)
【解决方案4】:

头文件

头文件应该只包含绝对必要的头文件。这意味着如果您从一个类派生或显式使用一个类作为成员,则来自另一个头文件。

如果你只使用一个类的引用或指针,那么只转发声明它(不包括 heder 文件)。

通过这种方式,您可以打破循环标头包含。

注意:您应该始终使用标头保护,因为标头可能通过多个路径包含在您的头文件用户不明显的路径中。

【讨论】:

    猜你喜欢
    • 2019-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-23
    • 2022-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多