我的包含文件存在轻微问题,我已经对我的问题进行了简化的模拟。 假设我正在编译一些需要名为
的头文件的源代码header.h
其中包含:
#ifndef HEADER_INCLUDED
#define HEADER_INCLUDED
#include element.h
typedef struct {
Element *list;
} Thing;
#endif
然后我有另一个头文件定义该元素并且还需要header.h。
element.h
#ifndef ELEMENT_INCLUDED
#define ELEMENT_INCLUDED
typedef struct Element;
#include header.h
void * func(Thing *myThing);
#endif
然后我遇到了一个问题,因为element.h不知道Thing类型是什么;我们还没有在header.h中达到那个定义,因为我们需要包含element.h。
我想我可以解决我的问题&#34; forward typedefing&#34; element.h中的Thing类型,就像<* p>之类的void * func原型之前
typedef struct thing Thing;
然后这就产生了另一个问题,并且编译器抱怨Thing存在冲突的类型。
如何摆脱这种混乱?
答案 0 :(得分:1)
你的主要问题是2之间存在循环依赖关系,但你正在使用防护宏。这些文件几乎就像复制粘贴一样 - 其中一个文件必须先包含在另一个文件中,因此您不能拥有这样的循环依赖。重新思考你的结构。
在一个位置声明/定义基本数据类型,然后使用它来定义派生/复合数据类型,最后是将这些类型作为参数/返回值的函数。
此外,typedef struct Element;
是无效的typedef。
答案 1 :(得分:0)
解决问题的最简单方法是将结构定义隔离在自己的标头中,并像往常一样受#ifndef / #define保护。如果你不想要这个单一结构的头文件,那么定义结构两次并用另一种#ifndef / #def以这种方式保护它的定义:
#ifndef __BOOLEAN_ENUM__
#define __BOOLEAN_ENUM__
enum boolean
{
false = 0,
true = 1
};
#endif
答案 2 :(得分:0)
header.h
不应包含element.h
。否则你有循环依赖。
您发布的代码存在大量错误。 (将来,您尝试编译的实际代码,而不是在编辑框中编写内容)。这是一个例子,我为了简洁省略了标题保护:
// header.h
struct Element; // actually not necessary, but may help with readability
typedef struct
{
struct Element *ptr;
} Thing;
和
// element.h
#include "header.h"
struct Element
{
int x;
};
typedef struct Element Element; // optional
void * func(Thing *myThing);
也可以在typedef struct Element Element;
中放置header.h
并在Element *ptr
的定义中使用Thing
,这是您喜欢哪种方式的品味问题。有些人不赞成在C语言中使用typedef
结构,但是我喜欢它,因为它意味着拼写错误导致立即编译错误,而不是默默地创建新类型。
如果您还希望element.h
不依赖header.h
,则可以对Thing
使用相同的技巧。你需要给它一个struct标签,就像struct Element
的方式一样。
答案 3 :(得分:0)
退出C代码和整个程序设计的事情。
很明显,&#34; Thing&#34; struct必须依赖于&#34;元素&#34; element.h中的struct。但是,使用依赖于&#34; Thing&#34;的功能并没有任何意义。从元素标题内部。最有意义的是使用&#34; Thing&#34;应该在&#34; Thing&#34;报头中。如果你使用面向对象的方法来看待它,你应该不管编程语言,那么Element就是一个类,Thing是一个类。该函数可以是Thing的成员函数,也可以是使用该类的非相关函数。
你在面向对象的C中做的是宣告&#34;元素&#34;和&#34;事情&#34;在各自的标题中作为不完整类型。类型定义对调用者是隐藏的,并且仅存在于那些头的相应C文件中,称为element.c和thing.c。处理各个类的所有成员函数将在头文件中声明并在C文件中定义。 (此设计有时也称为 opaque类型或不透明指针。)
使用任一类的函数将只包含所需的标题。