C 在两个不同的头文件中的两个结构中包含循环依赖项是否错误?
我有一个非常大的程序没有编译,我怀疑它与跨结构的循环依赖性有关。当我像下面这样编写它时,它将不会编译 foo.hC 在两个不同的头文件中的两个结构中包含循环依赖项是否错误?,c,struct,c-preprocessor,header-files,C,Struct,C Preprocessor,Header Files,我有一个非常大的程序没有编译,我怀疑它与跨结构的循环依赖性有关。当我像下面这样编写它时,它将不会编译 foo.h #ifndef FOO #define FOO #include "bar.h" typedef struct _foo Foo; struct _foo{ Bar *bar; } #endif #ifndef BAR #define BAR #include "foo.h" typedef struct _bar Bar; struct _bar{ Foo
#ifndef FOO
#define FOO
#include "bar.h"
typedef struct _foo Foo;
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "foo.h"
typedef struct _bar Bar;
struct _bar{
Foo *foo;
}
#endif
#ifndef COMMON
#define COMMON
typedef struct _foo Foo;
typedef struct _bar Bar;
#endif
#ifndef FOO
#define FOO
#include "common.h"
#include "bar.h"
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "common.h"
#include "foo.h"
struct _bar{
Foo *foo;
}
#endif
#ifndef BAR
#define BAR
struct _foo; //Defined in foo.h, circular dependency
struct _bar{
struct _foo *foo;
}
#endif
#ifndef FOO
#define FOO
struct _bar; //Defined in bar.h, circular dependency
struct _foo{
struct _bar *bar;
}
#endif
bar.h
#ifndef FOO
#define FOO
#include "bar.h"
typedef struct _foo Foo;
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "foo.h"
typedef struct _bar Bar;
struct _bar{
Foo *foo;
}
#endif
#ifndef COMMON
#define COMMON
typedef struct _foo Foo;
typedef struct _bar Bar;
#endif
#ifndef FOO
#define FOO
#include "common.h"
#include "bar.h"
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "common.h"
#include "foo.h"
struct _bar{
Foo *foo;
}
#endif
#ifndef BAR
#define BAR
struct _foo; //Defined in foo.h, circular dependency
struct _bar{
struct _foo *foo;
}
#endif
#ifndef FOO
#define FOO
struct _bar; //Defined in bar.h, circular dependency
struct _foo{
struct _bar *bar;
}
#endif
但是,如果我完全搞砸了我的设计,创建了一个common.h文件,并将所有的结构声明都放在其中,那么它似乎是可行的
common.h
#ifndef FOO
#define FOO
#include "bar.h"
typedef struct _foo Foo;
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "foo.h"
typedef struct _bar Bar;
struct _bar{
Foo *foo;
}
#endif
#ifndef COMMON
#define COMMON
typedef struct _foo Foo;
typedef struct _bar Bar;
#endif
#ifndef FOO
#define FOO
#include "common.h"
#include "bar.h"
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "common.h"
#include "foo.h"
struct _bar{
Foo *foo;
}
#endif
#ifndef BAR
#define BAR
struct _foo; //Defined in foo.h, circular dependency
struct _bar{
struct _foo *foo;
}
#endif
#ifndef FOO
#define FOO
struct _bar; //Defined in bar.h, circular dependency
struct _foo{
struct _bar *bar;
}
#endif
foo.h
#ifndef FOO
#define FOO
#include "bar.h"
typedef struct _foo Foo;
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "foo.h"
typedef struct _bar Bar;
struct _bar{
Foo *foo;
}
#endif
#ifndef COMMON
#define COMMON
typedef struct _foo Foo;
typedef struct _bar Bar;
#endif
#ifndef FOO
#define FOO
#include "common.h"
#include "bar.h"
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "common.h"
#include "foo.h"
struct _bar{
Foo *foo;
}
#endif
#ifndef BAR
#define BAR
struct _foo; //Defined in foo.h, circular dependency
struct _bar{
struct _foo *foo;
}
#endif
#ifndef FOO
#define FOO
struct _bar; //Defined in bar.h, circular dependency
struct _foo{
struct _bar *bar;
}
#endif
bar.h
#ifndef FOO
#define FOO
#include "bar.h"
typedef struct _foo Foo;
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "foo.h"
typedef struct _bar Bar;
struct _bar{
Foo *foo;
}
#endif
#ifndef COMMON
#define COMMON
typedef struct _foo Foo;
typedef struct _bar Bar;
#endif
#ifndef FOO
#define FOO
#include "common.h"
#include "bar.h"
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "common.h"
#include "foo.h"
struct _bar{
Foo *foo;
}
#endif
#ifndef BAR
#define BAR
struct _foo; //Defined in foo.h, circular dependency
struct _bar{
struct _foo *foo;
}
#endif
#ifndef FOO
#define FOO
struct _bar; //Defined in bar.h, circular dependency
struct _foo{
struct _bar *bar;
}
#endif
这看起来真是糟糕的设计。此外,我认为头部防护装置是为了防止循环包含引起的问题。我是应该使用common.h方法,还是我做了其他错误,导致我的第一个解决方案失败?我看到了一个明显的问题——在
foo.h
的标题保护上,您使用了结构的名称作为保护。这应该是宏的所有大写字母。我猜这是某种IDE自动替换,意外地溜进了你的代码
您遇到的问题可能不止于此,但仍然存在。=] 我发现了一个明显的问题——在foo.h
的头保护上,您使用结构的名称作为保护。这应该是宏的所有大写字母。我猜这是某种IDE自动替换,意外地溜进了你的代码
您遇到的问题可能不止于此,但仍然存在。=] 不同文件中的相互递归结构没有问题 这里的主要问题是圆形夹杂物不起作用。然而,解决这个问题很容易,因为两个标题都不必包含另一个 如果跳过
typedef
,可以执行以下操作:
// In a.h
struct a {
struct b *ptr;
};
及
或者
如果要使用typedef,只需跳过在结构定义中使用它即可
// In a.h
struct a {
// Have to use 'struct b' instead of 'b' because we can't guarantee
// that the typedef for b is visible yet.
struct b *ptr;
};
typedef struct a a;
及
不同文件中的相互递归结构没有问题 这里的主要问题是圆形夹杂物不起作用。然而,解决这个问题很容易,因为两个标题都不必包含另一个 如果跳过
typedef
,可以执行以下操作:
// In a.h
struct a {
struct b *ptr;
};
及
或者
如果要使用typedef,只需跳过在结构定义中使用它即可
// In a.h
struct a {
// Have to use 'struct b' instead of 'b' because we can't guarantee
// that the typedef for b is visible yet.
struct b *ptr;
};
typedef struct a a;
及
使用以下C文件:
#include <stdio.h>
#include "foo.h"
#include "bar.h"
int main()
{
Foo f = { NULL };
Bar b = { NULL };
printf("hello\n");
return 0;
}
请注意,
Foo
的typedef在它被引用之后出现。这就是导致错误的原因。由于Foo
和Bar
相互依赖,因此最好在同一标题中使用typedef为第一个文件定义这两者。使用以下C文件:
#include <stdio.h>
#include "foo.h"
#include "bar.h"
int main()
{
Foo f = { NULL };
Bar b = { NULL };
printf("hello\n");
return 0;
}
请注意,Foo
的typedef在它被引用之后出现。这就是导致错误的原因。由于Foo
和Bar
相互依赖,因此最好在同一个标题中定义这两种类型,并在第一个标题中使用typedef。在使用之前,必须声明(但不一定定义)每种类型。这在您的第一种方法中不会发生。假设您要在主程序中包含bar.h
。由于foo.h
包含在其中,并且由于头保护的结构,编译器生成如下内容:
typedef struct _foo Foo;
struct _foo{
Bar *bar;
}
typedef struct _bar Bar;
struct _bar{
Foo *foo;
}
int main( int argc, char* argv[] ){
//Program stuff
}
然后它尝试从上到下编译。问题是它符合定义
struct _foo{
Bar *bar;
}
而且不知道该做什么,因为编译器还没有看到Bar
解决方案是使用前向声明向编译器声明将有一个名为struct\u bar
的类型,并且您承诺稍后将定义此类型。例如,下面的编译非常好:
struct _bar; //Forward declaration of 'struct _bar'
struct _foo{ //Definition of 'struct _foo'
struct _bar myBar;
}
struct _bar{ //Definition of 'struct _bar'
struct _foo myFoo;
}
特别是在您的情况下,最好在一个专用的头文件中提交所有的前向声明,或者只在每个头文件中前向声明每个类型。例如:
bar.h
#ifndef FOO
#define FOO
#include "bar.h"
typedef struct _foo Foo;
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "foo.h"
typedef struct _bar Bar;
struct _bar{
Foo *foo;
}
#endif
#ifndef COMMON
#define COMMON
typedef struct _foo Foo;
typedef struct _bar Bar;
#endif
#ifndef FOO
#define FOO
#include "common.h"
#include "bar.h"
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "common.h"
#include "foo.h"
struct _bar{
Foo *foo;
}
#endif
#ifndef BAR
#define BAR
struct _foo; //Defined in foo.h, circular dependency
struct _bar{
struct _foo *foo;
}
#endif
#ifndef FOO
#define FOO
struct _bar; //Defined in bar.h, circular dependency
struct _foo{
struct _bar *bar;
}
#endif
foo.h
#ifndef FOO
#define FOO
#include "bar.h"
typedef struct _foo Foo;
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "foo.h"
typedef struct _bar Bar;
struct _bar{
Foo *foo;
}
#endif
#ifndef COMMON
#define COMMON
typedef struct _foo Foo;
typedef struct _bar Bar;
#endif
#ifndef FOO
#define FOO
#include "common.h"
#include "bar.h"
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "common.h"
#include "foo.h"
struct _bar{
Foo *foo;
}
#endif
#ifndef BAR
#define BAR
struct _foo; //Defined in foo.h, circular dependency
struct _bar{
struct _foo *foo;
}
#endif
#ifndef FOO
#define FOO
struct _bar; //Defined in bar.h, circular dependency
struct _foo{
struct _bar *bar;
}
#endif
正如评论中所指出的,头文件防护并不能为您“解决”这个问题——它们只是防止每个头文件被包含多次(这通常会导致重新定义错误)。正确的解决方案是确保编译器在使用之前知道要使用的每个类型。在使用之前必须声明(但不一定定义)每个类型。这在您的第一种方法中不会发生。假设您要在主程序中包含bar.h
。由于foo.h
包含在其中,并且由于头保护的结构,编译器生成如下内容:
typedef struct _foo Foo;
struct _foo{
Bar *bar;
}
typedef struct _bar Bar;
struct _bar{
Foo *foo;
}
int main( int argc, char* argv[] ){
//Program stuff
}
然后它尝试从上到下编译。问题是它符合定义
struct _foo{
Bar *bar;
}
而且不知道该做什么,因为编译器还没有看到Bar
解决方案是使用前向声明向编译器声明将有一个名为struct\u bar
的类型,并且您承诺稍后将定义此类型。例如,下面的编译非常好:
struct _bar; //Forward declaration of 'struct _bar'
struct _foo{ //Definition of 'struct _foo'
struct _bar myBar;
}
struct _bar{ //Definition of 'struct _bar'
struct _foo myFoo;
}
特别是在您的情况下,最好在一个专用的头文件中提交所有的前向声明,或者只在每个头文件中前向声明每个类型。例如:
bar.h
#ifndef FOO
#define FOO
#include "bar.h"
typedef struct _foo Foo;
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "foo.h"
typedef struct _bar Bar;
struct _bar{
Foo *foo;
}
#endif
#ifndef COMMON
#define COMMON
typedef struct _foo Foo;
typedef struct _bar Bar;
#endif
#ifndef FOO
#define FOO
#include "common.h"
#include "bar.h"
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "common.h"
#include "foo.h"
struct _bar{
Foo *foo;
}
#endif
#ifndef BAR
#define BAR
struct _foo; //Defined in foo.h, circular dependency
struct _bar{
struct _foo *foo;
}
#endif
#ifndef FOO
#define FOO
struct _bar; //Defined in bar.h, circular dependency
struct _foo{
struct _bar *bar;
}
#endif
foo.h
#ifndef FOO
#define FOO
#include "bar.h"
typedef struct _foo Foo;
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "foo.h"
typedef struct _bar Bar;
struct _bar{
Foo *foo;
}
#endif
#ifndef COMMON
#define COMMON
typedef struct _foo Foo;
typedef struct _bar Bar;
#endif
#ifndef FOO
#define FOO
#include "common.h"
#include "bar.h"
struct _foo{
Bar *bar;
}
#endif
#ifndef BAR
#define BAR
#include "common.h"
#include "foo.h"
struct _bar{
Foo *foo;
}
#endif
#ifndef BAR
#define BAR
struct _foo; //Defined in foo.h, circular dependency
struct _bar{
struct _foo *foo;
}
#endif
#ifndef FOO
#define FOO
struct _bar; //Defined in bar.h, circular dependency
struct _foo{
struct _bar *bar;
}
#endif
正如评论中所指出的,头文件防护并不能为您“解决”这个问题——它们只是防止每个头文件被包含多次(这通常会导致重新定义错误)。正确的解决方案是确保编译器在使用之前知道您将要使用的每种类型。对不起,我很快就搞定了。我现在就编辑对不起,我很快就搞定了。我将立即编辑“循环包含始终是错误的。”标题防护旨在防止循环包含引起的问题