首页 文章

解决循环typedef依赖?

提问于
浏览
30

在typedef这些结构中解决以下循环依赖的最佳方法是什么?
注意C语言标签 - 我正在寻找标准gcc C的解决方案 .

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

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

6 回答

  • 28

    前向声明其中一个结构:

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

    答案在于声明和定义之间的区别 . 您试图在同一步骤中声明和定义(在通过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类型 . 所以以下也可以,但是 NOT RECOMMENDED 因为它很脆弱:

    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之上),它将再次失败 . 这就是使这个脆弱的原因,因此不推荐 .

    请注意,如果包含指定类型的结构而不是指向它的指针,则此技巧不起作用 . 因此,例如,以下 WILL NOT compile

    typedef struct Bar Bar;
    
    struct Foo
    {
        Bar bar;
    };
    
    struct Bar
    {
        int i;
    };
    

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

    此代码 will compile

    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的定义之上,则它将无法编译,原因与前一个示例相同(不完整类型) .

  • 0

    至于可读性:

    typedef struct Foo_ Foo;
    typedef struct Bar_ Bar;
    
    struct Foo_ {
        Bar *bar;
    };
    
    struct Bar_ {
        Foo *foo;
    };
    

    完全避免 typedef struct 可能是个好主意;

  • 1

    由于 Person 只想要一个指向 People 的指针,所以只需预先声明后者即可:

    typedef struct People People;
    

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

    struct People {
        int count;
        int max;
        Person data[];
    };
    
  • 2
    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[]; 标准?

  • 41
    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;
    

相关问题