C头文件循环(C header file loops)

2019-07-19 03:58发布

我有一对夫妇的头文件,它归结为:

tree.h中:

#include "element.h"

typedef struct tree_
{
    struct *tree_ first_child;
    struct *tree_ next_sibling;
    int tag;
    element *obj;
    ....
} tree;

和element.h展开:

#include "tree.h"

typedef struct element_
{
    tree *tree_parent;
    char *name;
    ...
} element;

的问题是,它们都相互引用,所以树需要被包括元件,并且元件需要树被包括在内。

这不起作用,因为定义“树”结构,要素结构必须已经知道,但要定义元素结构,树形结构必须是已知的。

如何解决这些类型的循环(我想这可能是与“向前声明”?)的?

Answer 1:

我觉得这里的问题不是缺少后卫包括但事实上,这两个结构相互需要它们的定义。 所以这是一个类型定义翰和蛋的问题。

在C中的方式来解决这些或C ++是做前向声明的类型。 如果你告诉编译器元素是某种形式的结构,编译器能够产生一个指针。

内部tree.h中:

// tell the compiler that element is a structure typedef:
typedef struct element_ element;

typedef struct tree_ tree;
struct tree_
{
    tree *first_child;
    tree *next_sibling;
    int tag;

    // now you can declare pointers to the structure.
    element *obj;
};

这样,你就不必包括内部tree.h中element.h展开了。

你也应该把包括得分后卫身边的页头的文件。



Answer 2:

这里关键的观察是元素并不需要知道树的结构,因为它仅具有指向它。 同为树。 所有每个需要知道的是,存在一个类型有关的名称,没有什么在它。

因此,在tree.h中,而不是:

#include "element.h"

做:

typedef struct element_ element;

该“声明”类型“元素”和“结构element_”(说他们的存在),但没有“界定”他们(说他们是什么)。 所有你需要存储一个指针到嗒嗒是胡说声明,而不是它的定义。 只有当你要尊重它(例如读取成员)你需要定义。 在您的“.c”的文件中的代码需要做到这一点,但在这种情况下,你的头不。

有些人创建一个头文件,它前瞻性声明的所有类型在头一个群集,然后每个标题包含,而不是找出哪些类型的真正需要。 这是既不必需的也不是完全愚蠢的。

关于这些问题的答案包括警卫是错误的 - 他们一般是一个好主意,你应该了解他们,让自己一些,但他们不特别解决您的问题。



Answer 3:

正确的答案是使用包括警卫,并使用前置声明。

包括逆天

/* begin foo.h */
#ifndef _FOO_H
#define _FOO_H

// Your code here

#endif
/* end foo.h */

VISUAL C ++还支持的#pragma一次。 这是一个非标准的预处理指令。 为了换取编译器的便携性,可以减少预处理器名称冲突的可能性,并增加可读性。

前置声明

远期声明你的结构。 如果没有明确需要一个结构或类的成员,你可以在头文件的开头声明它们的存在。

struct tree;    /* element.h */
struct element; /* tree.h    */


Answer 4:

阅读关于前向声明 。

即。


// tree.h:
#ifndef TREE_H
#define TREE_H
struct element;
struct tree
{
    struct element *obj;
    ....
};

#endif

// element.h:
#ifndef ELEMENT_H
#define ELEMENT_H
struct tree;
struct element
{
    struct tree *tree_parent;
    ...
};
#endif


Answer 5:

这些被称为“一次性的头。” 见http://developer.apple.com/DOCUMENTATION/DeveloperTools/gcc-4.0.1/cpp/Once_002dOnly-Headers.html#Once_002dOnly-Headers



Answer 6:

包括守卫是有用的,但不解决这个海报的问题,这是对两个数据结构的递归依赖性。

这里的解决方案是申报树和/或元素的指针在头文件中的结构,这样你就不会需要包括.H

就像是:

struct element_;
typedef struct element_ element;

在tree.h中的顶部应该足以除去需要包括element.h展开

有了这样的局部声明中,您只能做与元素指针的东西,不需要编译器知道布局什么。



Answer 7:

恕我直言,最好的办法就是避免这种循环,因为它们是应该避免的物理couping的标志。

例如(据我记得) “面向对象设计启发式”的目的,以避免包括警卫,因为他们只掩盖循环(物理)的依赖。

另一方法是预先声明这样的结构:

 element.h: struct tree_; struct element_ { struct tree_ *tree_parent; char *name; }; 

tree.h中:结构element_; 结构tree_ {结构tree_ * FIRST_CHILD; 结构tree_ * NEXT_SIBLING; INT标签; 结构element_ * OBJ; };



Answer 8:

转发declaratio是与你能保证将有结构的tyoe将在后面的定义方式。



Answer 9:

我不喜欢向声明的事业,他们是多余的和马车。 如果你想在同一个地方所有的声明,那么你应该使用包括与包括警卫的头文件。

你应该考虑包括作为复制粘贴,当C preprocesor找到一个#include行只是放在myheader.h的在#include行被发现的相同位置的全部内容。

好吧,如果你写的包括警卫myheader.h的代码将被粘贴只有一个时间,其中第一的#include被发现。

如果你的程序有几个目标文件和问题,编译仍然存在,那么你应该使用正目标文件(这就像使用的extern)之间的声明,以只有一个类型声明保留对所有目标文件(编译混合所有声明在同一个表格,且必须标识是唯一的)。



Answer 10:

一个简单的解决方法就是没有单独的头文件。 毕竟,如果他们是互相依赖的,你永远不会使用一个没有其他的,所以为什么要分开呢? 你可以有两个使用相同的头,但提供了更集中的功能不同的.c文件。

我知道这并没有回答如何正确使用所有花哨的东西的问题,但我发现它的帮助时,我一直在寻找一种快速解决类似的问题。



文章来源: C header file loops