为什么包含防护不能防止链接器错误?

问题描述 投票:0回答:6

由于某种原因,即使我使用标头防护,我也会在标头文件中收到多个内容声明。我的示例代码如下:

main.c:

#include "thing.h"

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

    return 0;
}

东西.c:

#include "thing.h"

int increment(){
    return something++;
}

东西.h:

#ifndef THING_H_
#define THING_H_

#include <stdio.h>

int something = 0;

int increment();

#endif

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

c header include-guards
6个回答
13
投票

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

发生的情况是,包含

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

解决此问题的方法如下:

东西.c:

#include "thing.h"

int something = 0;

int increment(){
    return something++;
}

东西.h:

#ifndef THING_H_
#define THING_H_

#include <stdio.h>

extern int something;

int increment();

#endif

这样,只有

thing.c
才会有
something
的实例,并且
main.c
才会引用它。


4
投票

每个翻译单元都有一个定义(一个在

main.c
中,一个在
thing.c
中)。标头防护装置可防止标头多次包含在单个翻译单元中。

你需要在头文件中声明

something
,并且只需要在thing.c
定义
,就像函数一样:

东西.c:

#include "thing.h"

int something = 0;

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

东西.h:

#ifndef THING_H_
#define THING_H_

#include <stdio.h>

extern int something;

int increment(void);

#endif

4
投票

标头防护将阻止文件在同一编译单元(文件)中被多次编译。您将其包含在 main.c 和 thing.c 中,因此它将在每个单元中编译一次,从而导致变量

something
在每个单元中声明一次,或者总共声明两次。


1
投票

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


1
投票

变量

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

仅变量和函数原型的结构、宏和类型声明 应该在头文件中。在您的示例中,您可以在头文件中将

something
的类型声明为
extern int something
。但变量本身的定义应该在
.c
文件中。

完成后,变量

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


0
投票

ifndef
所守护的是一个
.h
多次包含在
.c
中。例如

东西。

#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
© www.soinside.com 2019 - 2024. All rights reserved.