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



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

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

包含保护对于防止单个翻译单元中的多个修饰或类型定义很有用,即自行编译的 .c 文件及其包含的所有标头。

假设您有以下不带包含防护的标头:

啊:

struct test {
int i;
};
struct test t1;

BH:

#include "a.h"
struct test *get_struct(void);

和以下主文件:

主.c:

#include <stdio.h>
#include "a.h"
#include "b.h"
int main()
{
struct test *t = get_struct();
printf("t->i=%dn", t->i);
return 0;
}

当预处理器运行时,生成的文件将如下所示(忽略 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=%dn", t->i);
return 0;
}

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

通过在 a.h 中添加包含防护:

#ifndef A_H
#define A_H
struct test {
int i;
};
struct test t1;
#endif

生成的预处理器输出为:

struct test {
int i;
};
struct test *get_struct(void);
int main()
{
struct test *t = get_struct();
printf("t->i=%dn", t->i);
return 0;
}

防止重复的结构定义。

但是现在让我们看看b.c,它构成了一个单独的翻译单元:

公元前:

#include "b.h"
struct test *get_struct(void)
{
return &t1;
}

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

struct test {
int i;
};
struct test t1;
struct test *get_struct(void);
struct test *get_struct(void)
{
return &t1;
}

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

现在我们链接a.o和b.o。 链接器发现 a.o 和 b.o 都包含一个名为t1的对象,因此链接失败,因为它被多次定义。

请注意,虽然包含保护阻止定义在单个翻译单元中多次出现,但它不会阻止它在多个翻译单元中发生。

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

extern struct test t1;

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

切勿在头文件中定义数据或函数(静态内联除外)。始终在 .c 源文件中执行此操作。如果要使它们在其他编译单元中可见,请在头文件中将它们声明为extern

如果您在许多编译单元中包含相同的 .h 文件,然后链接在一起,则防护不会保护您。

包含保护您多次包含相同的包含,它将使包含中的定义仅在第一个包含点处理一次。 这意味着您在保护商标之间所做的声明不会重复,因此不会产生有关双重定义的错误。 通常不是这种情况

extern type_of_variable variable_name;

您可以多次进行,而不会受到编译器的任何抱怨......它更多地与标头中包含的类型声明或static函数实现有关。

但是,您为什么不发布一个完整可编译代码的示例,并展示您正在尝试的内容以及为什么它不起作用。 从你的问题中,我无法猜测你假装做什么,如果某些事情在你的案例中不起作用(好吧,你引用了其他可能有答案的案例,那么你为什么不在那里使用答案呢? 那里给出的答案有什么问题?

请发布一个有效的例子来说明你担心的事情,并准确地解释为什么这些其他帖子不能解决你的问题(如果你有的话)

认为其中一个问题没有显示重复包含的实际内容,也没有显示实际的变量定义。 另一个是8年前关闭的问题,由于某种原因没有重新打开。 所以你冒着同样的风险(我确实冒着被否决的风险,这个答案实际上并没有回答你的问题,因为你实际上并没有问你发生了什么事——我不知道你的问题是否有实际问题)。

相关内容

  • 没有找到相关文章

最新更新