我有一对夫妇的头文件,它归结为:
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