如果每个标头都使用
#ifndef
,这是否意味着不会发生有关循环依赖的编译器错误?
不,不是。
这意味着编译器不会尝试包含无穷大的标头,但循环依赖仍然会带来逻辑问题,因为编译是从上到下执行的。让我们来看看为什么:
#ifndef A_H
#define A_H
#include "b.h"
struct A
{
B* ptr;
};
#endif
#ifndef B_H
#define B_H
#include "a.h"
struct B
{
A* ptr;
};
#endif
#include "a.h"
int main()
{
A a;
}
包含守卫使我们能够实际运行预处理器并让它在不到无限的时间内完成工作;事实上,速度太快了,我已经在下面手动完成了。结果是:
struct B
{
A* ptr;
};
struct A
{
B* ptr;
};
int main()
{
A a;
}
B
的定义位于A
的定义之前,因此无法理解A* ptr;
。当然,你可以解决这个问题,但只能通过颠倒包含的顺序,然后你就会遇到相反的问题。前向声明和/或重新架构是解决该问题的唯一方法。
标头防护解决了不同问题。它们不允许您简单地做任何您喜欢的事情。
它不会创建任何循环依赖关系,它会多次包含该文件,如名称“include”所示。当代码库很大并且我们不知道该文件是否已被另一个头文件包含时,通常会发生这种情况。
我们也可以使用单个语句,#pragma Once