C 使用循环引用定义结构字段

C 使用循环引用定义结构字段,c,struct,C,Struct,我有以下代码,其中一个结构字段依赖于一个尚未声明的结构字段,因为该结构反过来可能依赖于我试图声明的结构 我如何设计它以使其能够编译?或者我缺少一个明显的方法来摆脱联合结构,从而将多个结构定义保持在一起 typedef struct expression { expression_type type; union { bool_expression bool; identifier_expression ident; integer_

我有以下代码,其中一个结构字段依赖于一个尚未声明的结构字段,因为该结构反过来可能依赖于我试图声明的结构

我如何设计它以使其能够编译?或者我缺少一个明显的方法来摆脱联合结构,从而将多个结构定义保持在一起

typedef struct expression {
    expression_type type;
    union {
        bool_expression bool;
        identifier_expression ident;
        integer_expression _int;
        prefix_expression prefix;
        infix_expression infix;

        // TODO: Fix this
        if_expression _if;
    };
} expression;

typedef struct statement {
    token token;
    identifier name;
    expression * value;
} statement;

typedef struct block_statement {
    token token;
    statement *statements;
} block_statement;

typedef struct if_expression {
    token token;
    expression condition;
    block_statement *consequence;
    block_statement *alternative;
} if_expression;

在这种情况下,你不能


if_表达式
包含一个
表达式
,该表达式又包含一个
if_表达式
。如果使用指针解决此问题,则可以对定义重新排序,并使用
struct expression*
创建指向尚未定义的结构的指针。

在这种情况下,您不能


if_表达式
包含一个
表达式
,该表达式又包含一个
if_表达式
。如果使用指针解决此问题,则可以对定义重新排序,并使用
struct expression*
创建指向尚未定义的结构的指针。

如果更改
表达式条件
表达式*条件if_expression
中编码>并向前声明
expression
-
类型定义结构表达式在顶部,然后放置
结构表达式{…}在底部,代码应该是OK

/* Placeholder typedefs for undefined typedef names */
typedef int token;
typedef int identifier;
typedef int bool_expression;
typedef int identifier_expression;
typedef int integer_expression;
typedef int prefix_expression;
typedef int infix_expression;
typedef int expression_type;

/* The fixed code starts here */

typedef struct expression expression;

typedef struct statement
{
    token token;
    identifier name;
    expression * value;
} statement;

typedef struct block_statement
{
    token token;
    statement *statements;
} block_statement;

typedef struct if_expression
{
    token token;
    expression *condition;
    block_statement *consequence;
    block_statement *alternative;
} if_expression;

struct expression
{
    expression_type type;
    union
    {
        bool_expression bool;
        identifier_expression ident;
        integer_expression _int;
        prefix_expression prefix;
        infix_expression infix;
        if_expression _if;
    };
};

expression expr = { 0 };

这将编译。

如果您更改
表达式条件
表达式*条件if_expression
中编码>并向前声明
expression
-
类型定义结构表达式在顶部,然后放置
结构表达式{…}在底部,代码应该是OK

/* Placeholder typedefs for undefined typedef names */
typedef int token;
typedef int identifier;
typedef int bool_expression;
typedef int identifier_expression;
typedef int integer_expression;
typedef int prefix_expression;
typedef int infix_expression;
typedef int expression_type;

/* The fixed code starts here */

typedef struct expression expression;

typedef struct statement
{
    token token;
    identifier name;
    expression * value;
} statement;

typedef struct block_statement
{
    token token;
    statement *statements;
} block_statement;

typedef struct if_expression
{
    token token;
    expression *condition;
    block_statement *consequence;
    block_statement *alternative;
} if_expression;

struct expression
{
    expression_type type;
    union
    {
        bool_expression bool;
        identifier_expression ident;
        integer_expression _int;
        prefix_expression prefix;
        infix_expression infix;
        if_expression _if;
    };
};

expression expr = { 0 };

这将编译。

您最好删除
typedefs
,至少在开始时是这样,这样您才能更好地理解您的类型

您应该将结构更改为指向(而不是包含)其他结构,例如:

struct if_expression {
    /* struct? */ token *token;
    struct expression *condition;
    struct block_statement *consequence;
    struct block_statement *alternative;
}
当然,这将强制明智地使用
malloc()
free()
调用。在某些情况下,您可以稍后恢复到包含(如上面的
token
,因为不希望它指向您的其他结构,复制标记可能是一种廉价的操作)

对于循环引用,您可以在C中转发声明,也就是说,您告诉编译器“嘿,有一个名为expression的结构,它的内部结构您还不知道,但请相信我,您很快就会知道的”:


如果您以后决定使用
typedef
,那么您的代码会变得更加精简,请记住,结构可以有一个名称,typedef定义名称,并且这些名称不共享相同的命名空间。例如:

typedef struct {
    /* ...internal structure omited... */
} type_a;

typedef struct type_b {
    /* ...internal structure omited... */
} type_b;

typedef struct struct_c {
    /* ...internal structure omited... */
} type_c;

这里的
type\u a
是一个定义为匿名结构的类型。而
type_b
是一种定义为
struct type_b
的类型,即命名的(
type_b
)结构。而
type\u c
是一种定义为
struct-struct\u c
的类型,即命名的(
struct\u c
)结构

现在,将所有这些放在一起,您可以:

/* forward all your structs */
struct expression;
struct if_expression;
struct block_statement;

/* typedef them all */
typedef struct expression expression;
typedef struct if_expression if_expression;

/* actually define them */
struct expression {
    /* ... */
}


作为一个脚注,通过理解声明和定义之间的区别,您可以学到很多关于C语言的知识。

您最好删除
typedefs
,至少在最初,这样您就可以更好地理解您的类型

您应该将结构更改为指向(而不是包含)其他结构,例如:

struct if_expression {
    /* struct? */ token *token;
    struct expression *condition;
    struct block_statement *consequence;
    struct block_statement *alternative;
}
当然,这将强制明智地使用
malloc()
free()
调用。在某些情况下,您可以稍后恢复到包含(如上面的
token
,因为不希望它指向您的其他结构,复制标记可能是一种廉价的操作)

对于循环引用,您可以在C中转发声明,也就是说,您告诉编译器“嘿,有一个名为expression的结构,它的内部结构您还不知道,但请相信我,您很快就会知道的”:


如果您以后决定使用
typedef
,那么您的代码会变得更加精简,请记住,结构可以有一个名称,typedef定义名称,并且这些名称不共享相同的命名空间。例如:

typedef struct {
    /* ...internal structure omited... */
} type_a;

typedef struct type_b {
    /* ...internal structure omited... */
} type_b;

typedef struct struct_c {
    /* ...internal structure omited... */
} type_c;

这里的
type\u a
是一个定义为匿名结构的类型。而
type_b
是一种定义为
struct type_b
的类型,即命名的(
type_b
)结构。而
type\u c
是一种定义为
struct-struct\u c
的类型,即命名的(
struct\u c
)结构

现在,将所有这些放在一起,您可以:

/* forward all your structs */
struct expression;
struct if_expression;
struct block_statement;

/* typedef them all */
typedef struct expression expression;
typedef struct if_expression if_expression;

/* actually define them */
struct expression {
    /* ... */
}


作为一个脚注,通过理解声明和定义之间的区别,您可以学到很多关于C语言的知识。

您似乎正在尝试定义类型以捕获上下文无关的语言。你不能。解析时必须构建表达式树。因为
struct expression
具有
if\u expression\u if
具有
表达式条件,则代码>和
结构这是一个循环,因此不可能。你可以使用指针。在你的例子中,
如果表达式不是表达式而是语句。首先,去掉所有的typedef。它们没有任何好处,只是混淆了语法。如果需要(不需要),可以在定义结构后添加typedef。每个
If\u表达式
内部都有一个
表达式
,每个
表达式
内部都有一个
If\u表达式
。再加上一些其他的东西。一个
if_表达式使用了多少内存?似乎您正试图定义类型来捕获上下文无关的语言。你不能。解析时必须构建表达式树。因为
struct expression
具有
if\u expression\u if
具有
表达式条件,则代码>和
结构这是一个循环,因此不可能。你可以使用指针。在你的例子中,
if\u表达式