39

在对这些结构进行类型定义时,解决以下循环依赖的最佳方法是什么?
注意 C 语言标签 - 我正在寻找标准 gcc C 中的解决方案。

typedef struct {
    char* name;
    int age;
    int lefthanded;
    People* friends;
} Person;

typedef struct {
    int count;
    int max;
    Person* data;
} People;
4

6 回答 6

49

答案在于声明和定义之间的区别。您试图在同一步骤中声明和定义(在通过 typedef 的新类型的情况下)。您需要将它们分解为不同的步骤,以便编译器提前知道您在说什么。

typedef struct Person Person;
typedef struct People People;

struct Person {
    char* name;
    int age;
    int lefthanded;
    People* friends;
};

struct People {
    int count;
    int max;
    Person* data;
};

请注意在顶部添加了两个“空”类型定义(声明)。这告诉编译器新类型 Person 的类型是“struct Person”,因此当它在 struct People 的定义中看到它时,它就知道它的含义。

在您的特定情况下,您实际上可以只预先声明 People typdef,因为这是在定义之前使用的唯一类型。当您开始定义 struct People 时,您已经完全定义了 Person 类型。因此,以下内容也可以使用,但不推荐使用,因为它很脆弱:

typedef struct People People;

typedef struct {
    char* name;
    int age;
    int lefthanded;
    People* friends;
} Person;

struct People {
    int count;
    int max;
    Person* data;
};

如果您交换结构定义的顺序(将 struct People 移动到 Person 的 typedef 之上),它将再次失败。这就是使它变得脆弱的原因,因此不推荐。

请注意,如果您包含指定类型的结构而不是指向它的指针,则此技巧不起作用。因此,例如,以下内容将不会编译

typedef struct Bar Bar;

struct Foo
{
    Bar bar;
};

struct Bar
{
    int i;
};

上面的代码给出了一个编译器错误,因为当它试图在 struct Foo 的定义中使用 Bar 类型时它是不完整的。换句话说,它不知道要为结构成员“bar”分配多少空间,因为那时它还没有看到 struct bar 的定义。

此代码将编译

typedef struct Foo Foo;
typedef struct Bar Bar;
typedef struct FooBar FooBar;

struct Foo
{
    Bar *bar;
};

struct Bar
{
    Foo *foo;
};

struct FooBar
{
    Foo     foo;
    Bar     bar;
    FooBar  *foobar;
};

即使使用 Foo 和 Bar 中的循环指针,这也有效,因为类型 'Foo' 和 'Bar' 已预先声明(但尚未定义),因此编译器可以构建指向它们的指针。

当我们开始定义 FooBar 时,我们已经定义了 Foo 和 Bar 的大小,因此我们可以在其中包含实际的对象。我们还可以包含一个指向 FooBar 类型的自引用指针,因为我们已经预先声明了该类型。

请注意,如果您将 struct FooBar 的定义移到 struct Foo 或 Bar 的定义之上,则由于与前面示例相同的原因(不完整类型),它将无法编译。

于 2010-06-10T23:06:08.863 回答
35

前向声明结构之一:


struct people;

typedef struct {
  /* same as before */
  struct people* friends;
} Person;

typedef struct people {
  /* same as before */
} People;
于 2009-05-20T14:54:09.170 回答
6

至于可读性:

typedef struct Foo_ Foo;
typedef struct Bar_ Bar;

struct Foo_ {
    Bar *bar;
};

struct Bar_ {
    Foo *foo;
};

It might be a good idea to avoid typedef struct altogether;

于 2009-05-21T02:47:20.370 回答
2

由于Person只需要一个指向 的指针People,因此只需预先声明后者就可以了:

typedef struct People People;

然后将第二个声明更改为仅使用 struct 标记进行声明,如下所示:

struct People {
    int count;
    int max;
    Person data[];
};
于 2009-05-20T14:53:08.860 回答
1
struct _People;

typedef struct {
    char* name;
    int age;
    int lefthanded;
    struct _People* friends;
} Person;

struct _People {
    int count;
    int max;
    Person data[1];
};

注意:是Person data[];标准的吗?

于 2009-05-20T14:57:25.747 回答
0
struct People_struct;

typedef struct {
    char* name;
    int age;
    int lefthanded;
    struct People_struct* friends;
} Person;

typedef struct People_struct {
    int count;
    int max;
    Person data[];
} People;
于 2009-05-20T14:55:05.253 回答