循环#includes如何解决?
在c中假设我们有2个文件
1.h #include blah blah
我们有2.h.
#include code
这怎么解决?
通常,使用与文件名对应的ifndef / define保护include文件。 这不会阻止文件再次被包含,但它确实阻止了内容(在ifndef中)被使用并再次触发递归包含。
#ifndef HEADER_1_h #define HEADER_1_h #include "2.h" /// rest of 1.h #endif #ifndef HEADER_2_h #define HEADER_2_h #include "1.h" // rest of 2.h #endif
好的,为了完整起见,我将首先引用tvanfosson的答案:
你应该使用包含警戒:
// header1.hpp #ifndef MYPROJECT_HEADER1_HPP_INCLUDED #define MYPROJECT_HEADER1_HPP_INCLUDED /// Put your stuff here #endif // MYPROJECT_HEADER1_HPP_INCLUDED
但是,包含防护并不意味着解决循环依赖问题,它们旨在防止多个包含,这是完全不同的。
base.h / \ header1.h header2.h \ / class.cpp
在这种情况下(很常见),你只需要包含一次base.h,这就是包含警卫的内容。
所以这将有效地防止双重包含… 但你将无法编译!
可以通过尝试推理编译器来解释这个问题:
- 包含“header1.hpp”>这定义了包含守卫
- 包括“header2.hpp
- 尝试包含“header1.hpp”但不包括因为已经定义了包含保护
- 无法正确解析“header2.hpp”,因为来自“header1.hpp”的类型尚未定义(因为它被跳过)
- 回到“header1.hpp”,“header2.hpp”中的类型仍然缺失,因为它们无法编译,因此它也失败了
最后,你会留下一大堆错误信息,但至少编译器不会崩溃。
解决方案是以某种方式消除对此循环依赖的需要。
- 如果可能,使用前向声明
- 将“header1.h”拆分为2部分:独立于header2的部分和另一部分,你应该只需要在header2中包含前者
而这将解决循环依赖(手动)在编译器中没有任何魔法可以为你做。
必须消除循环内含物,而不是用包括警卫“解决”(如接受的答案所示)。 考虑一下:
1.H:
#ifndef HEADER_1_h #define HEADER_1_h #include "2.h" #define A 1 #define B 2 #endif // HEADER_1_h
·H:
#ifndef HEADER_2_h #define HEADER_2_h #include "1.h" #if (A == B) #error Impossible #endif #endif // HEADER_2_h
main.c中:
#include "1.h"
这将在编译时抛出“不可能”错误,因为“2.h”由于包含保护而未能包含“1.h”,并且A
和B
变为0.实际上,这导致难以跟踪错误根据包含头文件的顺序显示和消失。
这里正确的解决方案是将A
和B
移动到“common.h”,然后可以包含在“1.h”和“2.h”中。
既然您在c ++标签和c下发布了您的问题,那么我假设您使用的是c ++。 在c ++中,您还可以使用#pragma once编译器指令:
1.H:
#pragma once #include "2.h" /// rest of 1.h
·H:
#pragma once #include "1.h" /// rest of 2.h
结果是一样的。 但有一些注意事项:
-
pragma曾经通常会编译得更快,因为它是一个更高级别的机制,并且不会像包含警卫一样在预处理中发生
-
一些编译器已经知道错误“处理”#pragma一次。 虽然大多数(如果不是全部)现代编译器都能正确处理它。 有关详细列表,请参阅Wikipedia
编辑:我认为该指令在c编译器中也得到支持,但从未尝试过,而且,在我见过的大多数c程序中,包括防护是标准(可能是由于编译器限制处理pragma一次指令?)