如何解决 C 中的循环结构依赖关系
How to resolve circular struct dependencies in C
所以我有两个结构,为简单起见,我们将其称为A
和B
。 A
包含指向 B
和 B
[=32= 的指针] 包含一个 A
。所以这是代码:
a.h
#ifndef A_H
#define A_H
#include "b.h"
typedef struct _A {
B *b;
} A;
#endif
b.h
#ifndef B_H
#define B_H
#include "a.h"
typedef struct _B {
A a;
} B;
#endif
现在的问题是,当我从我的主 c 文件导入 a.h 时,我从 b.h 中收到关于 A 是未知类型的错误。我不确定如何解决这个问题。
这是一个解决方案,其中 header 都不需要知道另一个 header 使用的结构标签。 (值得注意的是,B.h
中的 struct B
可以更改为 struct foo
而 A.h
中没有任何变化。而且 A.h
根本不需要标签;struct A
可以删除。)此解决方案还允许源文件以任意顺序包含 header 或两个 header。
A.h
可以是:
#include "B.h"
#if !defined A_h
#define A_h
typedef struct A
{
B *b;
} A;
#endif // #if !defined A_h
和B.h
可以是:
#if !defined B_h
#define B_h
typedef struct B B;
#include "A.h"
typedef struct B
{
A a;
} B;
#endif // #if !defined B_h
B.h
通过执行 B
的部分(不完整)定义来工作,其中结构仅通过其标记而不是其内容已知。然后它包含 A.h
以获得有关 A
的完整信息,它仅通过指针使用 B
(允许用于不完整的结构类型)。 B.h
通过完全声明 B
.
结束
A.h
通过确保首先包含 B.h
来工作。它在其 header 守卫之前执行此操作,以便 B.h
中包含 A.h
将完全包含 B.h
需要的 A.h
。
这样做的方法是使用空定义预定义结构
typedef struct _A A;
typedef struct _B B;
typedef struct _A {
B *b;
} A;
typedef struct _B {
A a;
} B;
您可以将预定义放在一个全局包含文件中,以便从您需要的任何地方包含。
`
转发声明 struct _B
并删除 #incude "b.h"
in a.h
.
因为 a.h
只包含指向 B
的指针,所以不需要知道它的数据结构,所以在A
中我们只需要声明它的名字即可。
a.h
#ifndef A_H
#define A_H
struct _B; //forward declaration
typedef struct _A {
struct _B* b;
} A;
#endif
b.h
#ifndef B_H
#define B_H
#include "a.h"
typedef struct _B {
A a;
} B;
#endif
您需要了解声明和定义之间的区别。目前,我将 typedef
放在一边。为了能够做到这一点 definition:
struct A {
struct B *b;
};
您必须首先声明 struct B
。请注意,如果您在定义之前声明了某些内容,则该定义既算作定义又算作声明。但在这种情况下,由于循环依赖,我们需要单独声明。你可以解决这个问题:
struct A;
struct B;
这两行基本上是说"it exists two structs, and their names are A and B".
在大多数情况下,首选解决方案如下所示:
a.h
#ifndef A_H
#define A_H
typedef struct A A;
#endif
类似于 b.h
a.c
#include "a.h"
#include "b.h"
struct A {
struct B* B;
};
请注意,不要对结构和类型定义使用不同的名称,除非您有充分的理由不这样做。 (我打赌你不能)如果你决定这样做,不建议以下划线开头,因为这些是为将来使用保留的。
我写了一个关于这个话题的相关回答:
所以我有两个结构,为简单起见,我们将其称为A
和B
。 A
包含指向 B
和 B
[=32= 的指针] 包含一个 A
。所以这是代码:
a.h
#ifndef A_H
#define A_H
#include "b.h"
typedef struct _A {
B *b;
} A;
#endif
b.h
#ifndef B_H
#define B_H
#include "a.h"
typedef struct _B {
A a;
} B;
#endif
现在的问题是,当我从我的主 c 文件导入 a.h 时,我从 b.h 中收到关于 A 是未知类型的错误。我不确定如何解决这个问题。
这是一个解决方案,其中 header 都不需要知道另一个 header 使用的结构标签。 (值得注意的是,B.h
中的 struct B
可以更改为 struct foo
而 A.h
中没有任何变化。而且 A.h
根本不需要标签;struct A
可以删除。)此解决方案还允许源文件以任意顺序包含 header 或两个 header。
A.h
可以是:
#include "B.h"
#if !defined A_h
#define A_h
typedef struct A
{
B *b;
} A;
#endif // #if !defined A_h
和B.h
可以是:
#if !defined B_h
#define B_h
typedef struct B B;
#include "A.h"
typedef struct B
{
A a;
} B;
#endif // #if !defined B_h
B.h
通过执行 B
的部分(不完整)定义来工作,其中结构仅通过其标记而不是其内容已知。然后它包含 A.h
以获得有关 A
的完整信息,它仅通过指针使用 B
(允许用于不完整的结构类型)。 B.h
通过完全声明 B
.
A.h
通过确保首先包含 B.h
来工作。它在其 header 守卫之前执行此操作,以便 B.h
中包含 A.h
将完全包含 B.h
需要的 A.h
。
这样做的方法是使用空定义预定义结构
typedef struct _A A;
typedef struct _B B;
typedef struct _A {
B *b;
} A;
typedef struct _B {
A a;
} B;
您可以将预定义放在一个全局包含文件中,以便从您需要的任何地方包含。
`
转发声明 struct _B
并删除 #incude "b.h"
in a.h
.
因为 a.h
只包含指向 B
的指针,所以不需要知道它的数据结构,所以在A
中我们只需要声明它的名字即可。
a.h
#ifndef A_H
#define A_H
struct _B; //forward declaration
typedef struct _A {
struct _B* b;
} A;
#endif
b.h
#ifndef B_H
#define B_H
#include "a.h"
typedef struct _B {
A a;
} B;
#endif
您需要了解声明和定义之间的区别。目前,我将 typedef
放在一边。为了能够做到这一点 definition:
struct A {
struct B *b;
};
您必须首先声明 struct B
。请注意,如果您在定义之前声明了某些内容,则该定义既算作定义又算作声明。但在这种情况下,由于循环依赖,我们需要单独声明。你可以解决这个问题:
struct A;
struct B;
这两行基本上是说"it exists two structs, and their names are A and B".
在大多数情况下,首选解决方案如下所示:
a.h
#ifndef A_H
#define A_H
typedef struct A A;
#endif
类似于 b.h
a.c
#include "a.h"
#include "b.h"
struct A {
struct B* B;
};
请注意,不要对结构和类型定义使用不同的名称,除非您有充分的理由不这样做。 (我打赌你不能)如果你决定这样做,不建议以下划线开头,因为这些是为将来使用保留的。
我写了一个关于这个话题的相关回答: