循环#includes如何解决?

时间:2010-06-27 11:11:12

标签: c++ c

在c中假设我们有2个文件

1.h

#include<2.h>

blah blah

我们有      2.H

#include<1.h>

code

这是如何解决的?

4 个答案:

答案 0 :(得分:16)

通常,您使用与文件名对应的ifndef / define保护您的包含文件。这不会阻止文件再次被包含,但它确实会阻止使用内容(在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

答案 1 :(得分:7)

好的,为了完整起见,我将首先引用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”&gt;这定义了包含守卫
  • 包括“header2.hpp
  • 尝试包含“header1.hpp”但不包含因为已经定义了包含保护
  • 无法正确解析“header2.hpp”,因为来自“header1.hpp”的类型尚未定义(因为它被跳过)
  • 返回“header1.hpp”,“header2.hpp”中的类型仍然缺失,因为它们无法编译,因此也失败了

最后,你会留下一大堆错误信息,但至少编译器不会崩溃。

解决方案是以某种方式消除对此循环依赖的需要。

  • 尽可能使用前瞻性声明
  • 将“header1.h”分成两部分:独立于header2的部分和另一部分,你应该只需要在header2中包含前者

这将解决循环依赖(手动)在编译器中没有任何魔法可以为你做。

答案 2 :(得分:0)

循环内容必须消除,而不是“包含警卫”解决“(如接受的答案所示)。考虑一下:

1.H:

#ifndef HEADER_1_h
#define HEADER_1_h
#include "2.h"

#define A 1
#define B 2

#endif // HEADER_1_h

2.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”,并且AB都变为0。实际上,这会导致很难跟踪出现和消失的错误,具体取决于包含头文件的顺序。

这里的正确解决方案是将AB移至“common.h”,然后将其包括在“1.h”和“2.h”中。

答案 3 :(得分:-1)

既然您在c ++标签和c下发布了您的问题,那么我假设您使用的是c ++。在c ++中,您还可以使用 #pragma once 编译器指令:

1.H:

#pragma once
#include "2.h"
/// rest of 1.h 

2.H:

#pragma once
#include "1.h"
/// rest of 2.h 

结果是一样的。但有一些注意事项:

  1. pragma一般会编译得更快,因为它是一个更高级别的机制,并且不会像包含警卫一样在预处理中发生

  2. 有些编译器已经知道错误“处理”#pragma一次。虽然大多数(如果不是全部)现代编译器都能正确处理它。有关详细列表,请参阅Wikipedia

  3. 编辑:我认为c编译器也支持该指令,但从未尝试过,而且,在我看过的大多数c程序中,包括防护是标准(可能是由于编译器限制处理pragma一次指令? )