【问题标题】:Header/Include guards don't work?标题/包含警卫不起作用?
【发布时间】:2011-12-17 02:15:50
【问题描述】:

出于某种原因,即使我使用了标头保护,我也会在我的头文件中获得多个内容声明。我的示例代码如下:

main.c:

#include "thing.h"

int main(){
    printf("%d", increment());

    return 0;
}

thing.c:

#include "thing.h"

int increment(){
    return something++;
}

thing.h:

#ifndef THING_H_
#define THING_H_

#include <stdio.h>

int something = 0;

int increment();

#endif

当我尝试编译它时,GCC 说我对 something 变量有多个定义。 ifndef 应该确保不会发生这种情况,所以我很困惑为什么会这样。

【问题讨论】:

  • 编译器错误“多个声明”与链接器错误“多个定义”不同”。您在问题中都提到了(实际上唯一的问题是后者);了解差异是了解问题所在的关键。标头保护防止多个声明,而不是多个定义
  • @Clifford 抱歉,我应该提到我遇到了链接器错误。
  • 另外,在 C 中,int increment(); 不是原型,而是声明了一个带有未指定数量参数的函数。为此使用int increment(void);

标签: c header include-guards


【解决方案1】:

包含防护功能正常,不是问题的根源。

发生的情况是每个包含thing.h 的编译单元都有自己的int something = 0,因此链接器会抱怨多个定义。

以下是解决此问题的方法:

thing.c:

#include "thing.h"

int something = 0;

int increment(){
    return something++;
}

thing.h:

#ifndef THING_H_
#define THING_H_

#include <stdio.h>

extern int something;

int increment();

#endif

这样,只有thing.c 会有something 的实例,main.c 会引用它。

【讨论】:

  • 您不妨补充一点,即使没有多重定义错误,每个 TU 也将拥有自己的变量副本,它不会达到在所有 TU 之间共享相同变量的目的。源文件。
【解决方案2】:

每个翻译单元中都有一个定义(main.c 中有一个定义,thing.c 中有一个定义)。标头保护阻止标头在单个翻译单元中多次包含。

你需要在头文件中声明something,并且只在thing.c定义它,就像函数一样:

thing.c:

#include "thing.h"

int something = 0;

int increment(void)
{
    return something++;
}

thing.h:

#ifndef THING_H_
#define THING_H_

#include <stdio.h>

extern int something;

int increment(void);

#endif

【讨论】:

    【解决方案3】:

    标头保护将阻止文件在同一编译单元(文件)中多次编译。您将它包含在 main.c 和 thing.c 中,因此它将在每个单元中编译一次,从而导致变量 something 在每个单元中声明一次,或总共声明两次。

    【讨论】:

      【解决方案4】:

      尽量避免全局定义变量。 使用像 increment() 这样的函数来修改和读取它的值。 这样你就可以在 thing.c 文件中保持变量静态,并且你肯定知道只有该文件中的函数会修改该值。

      【讨论】:

      • 啊,这就是您在 C 中避免全局变量的方法。感谢您提供的信息。
      【解决方案5】:

      变量something 应该在.c 文件中定义,而不是 在头文件中。

      仅变量和函数原型的结构、宏和类型声明 应该在头文件中。在您的示例中,您可以在头文件中将something 的类型声明为extern int something。但是变量本身的定义应该在.c文件中。

      随着你所做的,变量something将被定义 在 每个 .c 包含 thing.h 的文件中,您会得到一个 GCC 尝试链接时出现“多次定义的内容”错误消息 一切都在一起。

      【讨论】:

      • 你的第一个语句不正确。变量应该在头文件中extern关键字declared并在defined中唯一的源文件。
      【解决方案6】:

      ifndef 保护的是.h 不止一次包含在.c 中。例如

      东西。 h

      #ifndef
      #define
      
      int something = 0;
      #endif
      

      thing2.h

      #include "thing.h"
      

      main.c

      #include "thing.h"
      #include "thing2.h"
      int main()
      {
        printf("%d", something);
        return 0;
      }
      

      如果我离开 ifndef,那么 GCC 会抱怨

       In file included from thing2.h:1:0,
                   from main.c:2:
      thing.h:3:5: error: redefinition of ‘something’
      thing.h:3:5: note: previous definition of ‘something’ was here
      

      【讨论】:

      • 虽然您的解释是正确的,但 OP 的问题不在于,包含防护绝对是就地
      • 鉴于我在这里读到的内容,我可以同意@manuzhang。出于形式考虑,我将保留它们,但我不打算在一个编译单元中多次包含标头。 :)
      • 嗯,对于较大的项目,您必须这样做,这就是 ifndef 的用武之地
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多