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表达式