【问题标题】:Adding an include guard breaks the build添加包含保护会破坏构建
【发布时间】:2009-11-16 19:01:01
【问题描述】:

我将#ifndef..#define..#endif 添加到我的项目文件中,但编译器失败。一旦我删除它或在定义中添加任何其他名称,它就可以正常编译。可能是什么问题呢?

听起来文件已经被声明了,但我不知道在哪里。我可以删除它,但我真的很想知道为什么会这样。

error: expected class-name before ‘{’ token
error: ‘QDesignerFormEditorInterface’ has not been declared

还有一些其他错误。

我实际上使用的是 Qt 中的一个示例,“Custom Widget Plugin Example”。

不同之处在于我将自己的类用于自定义小部件(.h、.cpp 和 .ui 文件)。

这可能与包含 2 个包含的文件有关,尽管示例是这样做的。

【问题讨论】:

  • 描述文件。解释您要添加的#ifndef 内容以及原因。如果它是标准的包含防护,并且您做得对,那么您可能正在复制包含防护的名称。在您的代码库中搜索它,并在将来使用更多不同的名称(直接基于整个文件名的名称通常是安全的)。
  • 失败的不是构建,而是一个编译单元。这是一个编译时错误,所以添加编译失败的单元肯定是可能的。

标签: c++ compiler-errors macros header include-guards


【解决方案1】:

此宏是否用作include guard?如果是这样,听起来您正在复制其他地方使用的名称。当人们不考虑包含保护必须具有的范围时,这是一个常见问题 - 您应该在其中包含更多信息,而不仅仅是文件名。

包括后卫目标:

  • 在创建标头时生成一次
  • 再也不用考虑了
  • 复制的机会小于中奖的机会

错误的包含保护名称(对于文件“config.h”):

  • CONFIG_H
    • 太笼统了
  • _CONFIG_HCONFIG__HCONFIG_H____CONFIG_H__
  • PROJECT_CONFIG_H
    • 更好,不太可能在不相关的项目中重复
    • 但仍然没有路径信息,容易在大型项目中复制

良好的包含保护名称(用于文件“config.h”):

  • PATE_20091116_142045
    • 那是<last name>_<date>_<time>
    • 甚至不需要项目、路径、文件名信息
    • 易于键入
      • 如果您的编辑器具有插入日期功能,您可以非常快速地“输入”它
    • 易于生成
      • 生成时包含一个序列号,如果您需要每秒生成一个以上
    • 强有力的保证是普遍独一无二的
  • INCLUDE_GUARD_726F6B522BAA40A0B7F73C380AD37E6B
    • 从实际的UUID 生成
      • 强有力的保证是普遍独一无二的
    • 如果意外出现,“INCLUDE_GUARD”可以很好地提示它是什么,同时将它放在一个单独的命名空间中(尽管按照惯例,而不是被语言识别)
    • 根据需要添加项目名称(宏的项目指南通常要求)
    • 轻松编写自己的sample program 以生成

【讨论】:

  • #pragma once - 最好的包含保护(如果您的目标编译器支持)
  • 除了#pragma 引入了关于支持和非标准的辩论,没有额外的好处。它易于使用,包括警卫。
  • 一个潜在的额外好处是编译器可以构建一个头文件名的集合,这些头文件名曾经在其中使用过#pragma,甚至不再打开文件,而不必打开文件,阅读它所有,解析它并忽略它。也就是说,我同时使用了这两种方法,并且 #pragma 一旦受到编译器版本检查的保护......
  • 编译器可以通过包含防护来做到这一点。 GCC 多年来一直这样做,我听说 MSVC 现在也这样做了。一个重要的问题是如何处理链接(符号链接和硬链接)之类的东西——#pragma 失败,但包含守卫工作。
【解决方案2】:

如果您为已定义的常量添加#ifndef,它将始终验证为真。您说“已声明文件”,但未声明文件。您应该检查的确实是您放在​​#ifndef 之后的常量。对整个源代码树进行简单搜索,然后仔细检查当前 #define 出现的顺序。

当然还有:您的代码正确吗?尝试使用垃圾名称作为常量,并在其后放置#endif:如果仍然错误,则您有拼写错误(如果有,请粘贴您的代码)。另见this post

PS:我看到 David Thornley 在评论中输入了类似的建议...抱歉,如果这与此线程中的信息重复。

【讨论】:

  • 正如我所说,当我将垃圾作为常量时,一切都编译得很好。
  • 那么,在我看来,您确实应该使用垃圾(名称真的无关紧要),因为引起麻烦的名称显然已经在其他地方声明了。如另一个答案中所述,常量可以是任何名称。如果范围只是本地的,那么不要打扰并保留您的工作垃圾般的名称。
  • 我希望了解为什么会这样。
  • 也许我不清楚。一定要好好看看佩特的回答,它相当广泛。如果定义了XYZ,并且你有#ifndef XYZ,它总是会失败。如果您想要相反,请使用未定义的名称。恐怕这就是所有的“为什么”
  • 好的,我会调查的。对不起,我在工作,今天没有太多时间看。谢谢你的回答
猜你喜欢
  • 2021-08-05
  • 1970-01-01
  • 2015-04-30
  • 2014-09-10
  • 2016-01-22
  • 1970-01-01
  • 2018-11-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多