答案在于声明和定义的区别。您试图在同一步骤中声明和定义(在通过 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'分配多少空间,因为那时它还没有看到结构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 的定义之上,则由于与上一个示例相同的原因(不完整类型),它将无法编译。