39

これらの構造体をtypedefする際に、次の循環依存関係を解決するための最良の方法は何ですか?
C言語タグに注意してください-私は標準のgccCで解決策を探しています。

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;
};

上部に2つの「空の」typedefが追加されていることに注意してください(宣言)。これは、新しい型Personが型'struct Person'であることをコンパイラーに通知するため、struct Peopleの定義内でそれを見ると、それが何を意味するのかがわかります。

あなたの特定のケースでは、それが定義される前に使用される唯一のタイプであるため、Peopletypdefを事前に宣言するだけで実際に回避することができます。構造体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が不完全であるため、コンパイラエラーが発生します。つまり、その時点で構造体バーの定義が表示されていないため、構造体メンバー「バー」に割り当てるスペースがわかりません。

このコードはコンパイルされます

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への自己参照ポインターを含めることもできます。

structFooBarの定義をstructFooまたはBarの定義の上に移動した場合、前の例(不完全な型)と同じ理由でコンパイルされないことに注意してください。

于 2010-06-10T23:06:08.863 に答える
35

構造体の1つを前方宣言します。


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;
};

typedef struct完全に避けるのは良い考えかもしれません。

于 2009-05-21T02:47:20.370 に答える
2

Personへのポインタが必要なだけなのでPeople、後者を事前に宣言するだけで問題ありません。

typedef struct People People;

次に、2番目の宣言を次のように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 に答える