【问题标题】:How to define a typedef struct inside another one with anonymous union? [duplicate]如何使用匿名联合在另一个结构中定义 typedef 结构? [复制]
【发布时间】:2020-04-29 20:07:55
【问题描述】:

我想表示一个嵌套的 ast 节点

typedef struct ast_assignment
{
    char* sym;
    ast_node* value;
} ast_assignment;

typedef struct ast_conjunction
{
    char* sym;
    ast_node* value;
} ast_conjunction;

typedef struct ast_node {
  int node_type;
  union {
    ast_assignment data;
    ast_conjunction data;
  };
} ast_node;

但无论我先定义什么,编译器都会告诉我另一个结构是未知类型?如何进行?

【问题讨论】:

  • 哪个其他结构?这段代码看起来不会编译 - 它需要在每个 typedef 的结束 } 之后加上一个分号,并且没有一个 typedef 实际上提供名称。
  • 抱歉复制粘贴了一些片段用于演示。通常第一个请求是代码

标签: c typedef


【解决方案1】:
  • Typedef 必须描述一个实际的类型名称
  • Typedef 后面需要 ;
  • 循环类型引用需要一些特殊的调味料
  • 联合需要不同的成员名称

你的意思是:

struct ast_node; // forward declaration

typedef struct {
    char* sym;
    struct ast_node* value;
} ast_assignment;

typedef struct ast_conjunction {
    char  * sym;
    struct ast_node* value;
} ast_conjunction;

typedef struct ast_node {
    int node_type;
    union {
        ast_assignment  data_asg;
        ast_conjunction data_conj;
    };
} ast_node;

稍微扩展一下以获得更完整的答案。

首先,typedef 的目的是将一个新名称安装到您可以使用的编译器中,因此typedef struct { ... }; 并没有真正做太多事情。它应该是typedef struct {...} newtype;,因此您可以使用实际名称newtype

它后面还需要一个分号,每次我从 C# 回到 C 时都会把我搞砸 :-)

循环引用很棘手,提前使用struct mytype; 意味着您可以使用该名称mytype 只有在它是在不需要了解结构细节的情况下为人所知。在实践中,这意味着您可以使用 struct mytype * 作为指针 - 因为这是固定大小 - 但这是不允许的:

struct ast_node; // forward declaration

struct some_other_type {
    struct ast_node *nodeptr;  // this is ok
    struct ast_node  thisnode; // FAIL
    ...
};

原因是:无论指针指向什么类型的数据,指针都是固定大小的,所以编译器会带你一点,但thisnode 需要了解所有细节。抱歉,没办法。

Re:联合,你不能用两个同名成员定义任何unionstruct,因为你怎么能引用其中一个而编译器会知道哪个?

我个人不喜欢将typedef 用于结构类型,所以我会这样做:

struct ast_node; // forward struct defn

struct asg_assignment {
    char *sym;
    struct ast_node *value;
};

struct ast_conjunction {
    char  * sym;
    struct ast_node* value;
};

struct ast_node {
    int node_type;
    union {
        struct ast_assignment  data_asg;
        struct ast_conjunction data_conj;
    };
};

...但我不确定我是否可以通过个人喜好以外的任何理由来证明这一点。

【讨论】:

    【解决方案2】:

    您的代码中有多个错误。声明结构体的正确方法如下:

    struct a {
        ...
    };  // needs a semicolon
    

    要引用它,您还必须使用struct 关键字;

    struct b {
        struct a data;
    };
    

    在您的情况下,将编译的正确代码是:

    struct ast_assignment
    {
        char* sym;
        struct ast_node* value;
    };
    
    struct ast_conjunction
    {
        char* sym;
        struct ast_node* value;
    };
    
    struct ast_node {
      int node_type;
      union {
        struct ast_assignment data_assignment;
        struct ast_conjunction data_conjunction;  // you cannot have multiple members with the same name
      };
    };
    

    【讨论】:

      【解决方案3】:

      在 C 语言中,必须先声明你想要 caöl 的类型。

      但是,您可以只使用另一个指针,例如 void*

      void* 是一个可以用于任何类型的指针。

      如果你在第一个结构中定义后面结构的类型为void*,编译器将允许它。

      但是这有缺点。您正在失去类型安全性,您可能需要在某些时候进行转换。

      另外,typedef 快​​捷方式不允许在声明整个 typedef 之前使用它。

      这意味着,你不能在结构中使用快捷方式。

      例如,以下是不可能的:

      typedef struct mystruct{
          myStruct_t *myValue;
      } myStruct_t;
      

      您需要这样做:

      typedef struct mystruct{
          struct myStruct *myValue;
      } myStruct_t;
      

      【讨论】:

      • void 是一种选择,但在我的情况下不是,tnx
      猜你喜欢
      • 2021-11-06
      • 2015-05-24
      • 1970-01-01
      • 2014-10-21
      • 2019-06-02
      • 1970-01-01
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      相关资源
      最近更新 更多