C:外部变量声明和包含守卫

drd*_*hin 0 c include-guards include

关于在头文件中声明变量,我遇到了与这两篇文章(第一篇第二篇)中描述的相同的问题。列出的解决方案对我来说效果很好,但我对解决方案有一个基本问题:

为什么包含守卫仍然不能解决这个问题?如果我多次包含相同的头文件,我希望包含守卫会避免多次声明我的变量。

dbu*_*ush 5

包含保护对于防止单个翻译单元中的多个声明或类型定义非常有用,即一个 .c 文件与它包含的所有头文件一起编译。

假设您有以下不包含保护的标题:

啊:

struct test {
    int i;
};

struct test t1;
Run Code Online (Sandbox Code Playgroud)

哈:

#include "a.h"

struct test *get_struct(void);
Run Code Online (Sandbox Code Playgroud)

以及以下主文件:

主文件:

#include <stdio.h>
#include "a.h"
#include "b.h"

int main()
{
    struct test *t = get_struct();
    printf("t->i=%d\n", t->i);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当预处理器在 上运行时,生成的文件将如下所示(忽略 stdio.h 的内容):

struct test {
    int i;
};

struct test t1;

struct test {
    int i;
};

struct test t1;

struct test *get_struct(void);

int main()
{
    struct test *t = get_struct();
    printf("t->i=%d\n", t->i);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

因为main.c包含ah和bh,又因为bh也包含ah,所以ah的内容出现了两次。这会导致struct test被定义两次,这是一个错误。但是变量没有问题,t1因为每个都构成了一个暂定定义,并且一个翻译单元中的多个暂定定义被组合以引用在结果 main.o 中定义的单个对象。

通过向 ah 添加包含守卫:

#ifndef A_H
#define A_H

struct test {
    int i;
};

struct test t1;

#endif
Run Code Online (Sandbox Code Playgroud)

结果预处理器输出将是:

struct test {
    int i;
};

struct test *get_struct(void);

int main()
{
    struct test *t = get_struct();
    printf("t->i=%d\n", t->i);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

防止重复的结构定义。

但是现在让我们看看 bc 构成一个单独的翻译单元:

公元前:

#include "b.h"

struct test *get_struct(void)
{
    return &t1;
}
Run Code Online (Sandbox Code Playgroud)

预处理器运行后,我们有:

struct test {
    int i;
};

struct test t1;

struct test *get_struct(void);

struct test *get_struct(void)
{
    return &t1;
}
Run Code Online (Sandbox Code Playgroud)

这个文件可以很好地编译,因为有一个定义,struct test并且一个暂定定义t1给了我们一个在 bo 中定义的对象

现在我们链接 ao 和 bo 链接器看到 ao 和 bo 都包含一个名为 的对象t1,因此链接失败,因为它被定义了多次。

请注意,虽然包含守卫防止定义在单个翻译单元中出现多次,但并不能防止它在多个翻译单元中发生。

这就是为什么t1应该在 ah 中有一个外部声明:

extern struct test t1;
Run Code Online (Sandbox Code Playgroud)

以及一个.c 文件中的非外部声明。