drd*_*hin 0 c include-guards include
关于在头文件中声明变量,我遇到了与这两篇文章(第一篇和第二篇)中描述的相同的问题。列出的解决方案对我来说效果很好,但我对解决方案有一个基本问题:
为什么包含守卫仍然不能解决这个问题?如果我多次包含相同的头文件,我希望包含守卫会避免多次声明我的变量。
包含保护对于防止单个翻译单元中的多个声明或类型定义非常有用,即一个 .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 文件中的非外部声明。
| 归档时间: |
|
| 查看次数: |
68 次 |
| 最近记录: |