在typedef这些结构中解决以下循环依赖的最佳方法是什么?
注意C语言标签 - 我正在寻找标准gcc C的解决方案.
typedef struct { char* name; int age; int lefthanded; People* friends; } Person; typedef struct { int count; int max; Person* data; } People;
小智.. 43
答案在于声明和定义之间的区别.您试图在同一步骤中声明和定义(在通过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; };
注意在顶部添加了两个"空"typedef(声明).这告诉编译器新类型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; };
如果交换结构定义的顺序(将结构人员移动到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的定义之上,则它将无法编译,原因与上一个示例相同(不完整类型).
答案在于声明和定义之间的区别.您试图在同一步骤中声明和定义(在通过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; };
注意在顶部添加了两个"空"typedef(声明).这告诉编译器新类型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; };
如果交换结构定义的顺序(将结构人员移动到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的定义之上,则它将无法编译,原因与上一个示例相同(不完整类型).
向前声明其中一个结构:
struct people; typedef struct { /* same as before */ struct people* friends; } Person; typedef struct people { /* same as before */ } People;
至于可读性:
typedef struct Foo_ Foo; typedef struct Bar_ Bar; struct Foo_ { Bar *bar; }; struct Bar_ { Foo *foo; };
typedef struct
完全避免这可能是一个好主意;