C语言中的相互依赖结构

C语言中的相互依赖结构,c,struct,enums,unions,forward-declaration,C,Struct,Enums,Unions,Forward Declaration,我正在关注Ruslan Spivak的文章系列/教程“让我们构建一个简单的解释器”,这是一个用Python构建简单Pascal解释器的指南。我正试图学习C语言。关于添加抽象语法树的部分让我感到困惑 我有这个头文件: #包括“tokens.h” 结构双节点 { 结构节点左; 令牌op; 结构节点权限; }; 结构节点 { 联合价值; 枚举类型; }; 枚举类型 { 号码, 比诺普, }; 联合价值 { 结构二进制节点二进制; 结构numnode num; }; 结构节点 { 令牌tok; };

我正在关注Ruslan Spivak的文章系列/教程“让我们构建一个简单的解释器”,这是一个用Python构建简单Pascal解释器的指南。我正试图学习C语言。关于添加抽象语法树的部分让我感到困惑

我有这个头文件:

#包括“tokens.h”
结构双节点
{
结构节点左;
令牌op;
结构节点权限;
};
结构节点
{
联合价值;
枚举类型;
};
枚举类型
{
号码,
比诺普,
};
联合价值
{
结构二进制节点二进制;
结构numnode num;
};
结构节点
{
令牌tok;
};
其中,
“tokens.h”
包括
令牌
类型定义
'd结构

我的问题是我的编译器:

Apple clang version 12.0.5 (clang-1205.0.22.9)
Target: x86_64-apple-darwin20.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
抛出
不完整类型
错误

从这些链接:



我的猜测是我必须使用指针,但我完全不知道在哪里。

在Python中,对象不能包含其他对象。Python中的对象只能包含对另一个对象的引用

因此,在Python中,
BinOp
类的对象包含三个引用-
self.left
self、right
self.op
。但它实际上并不包含三个对象

C
中,一个结构实际上可以包含其他结构。因此,一个
struct binop
类型的对象(在C中,单词“object”只是指一个被解释为特定类型的内存区域,与Python对象不太相似)将包含两个
struct node
类型的对象以及一个
token
类型的对象

在C中,所有类型都必须有一个大小。让我们找出一些大小的下限(这些只是下限,因为我们必须考虑填充)

sizeof(struct binop)>=sizeof(struct node)+sizeof(token)+sizeof(struct node)

sizeof(结构节点)>=sizeof(union nvalue)+sizeof(enum ntype)

sizeof(union-nvalue)>=min(sizeof(struct-binop)、sizeof(struct-numnode))>=sizeof(struct-binop)

所以我们知道
sizeof(struct binop)>=sizeof(struct node)+sizeof(token)+sizeof(struct node)>sizeof(struct node)>=sizeof(union nvalue)>=sizeof(struct binop)

因此,
sizeof(structbinop)>sizeof(structbinop)

这是一个问题,因为数字不能大于自身。所以
C
无法为您编译此代码,因为它不知道
struct binop
应该有多大

事实上,每当一个
struct
以这种方式包含自己时,如果没有指针,这将导致一个严重的问题

好消息是,我们可以通过重新定义

联合值{
结构binopnode*binop,
结构numnode num
}

现在,我们可以将
union nvalue的大小计算为
min(sizeof(struct binopnode*)、sizeof(struct numnode))
。这是完全正确的,因为指针的大小是固定的(在64位系统上,函数指针以外的任何指针的大小都是
8

您可以先声明结构,然后再将其作为指针引用

在C中,当一个结构a包含另一个结构B时,a将需要内存区域来容纳B的大小。如果结构a包含结构B,而结构B包含结构a,编译器无法决定应该为每个结构分配多少内存。所以,如果您想使用相互引用的结构,您应该至少使用其中一个作为指针

#包括“tokens.h”
结构双节点;
结构节点;
枚举类型;
联合价值观;
结构节点;
结构双节点
{
结构节点*左;
令牌op;
结构节点*右;
};
结构节点
{
联合价值*价值;
枚举类型;
};
枚举类型
{
号码,
比诺普,
};
联合价值
{
结构binopnode*binop;
结构numnode*num;
};
结构节点
{
令牌tok;
};

必须使用指针:
struct node*left
而不是
struct node left
等。在
struct binopnode
中使用
struct node*
是正确的。请注意,原始的:
struct node left
无法编译,因为
struct node{
定义必须在
struct binopcode{
之前。指针可以指向部分定义的项,但不能指向完整的子结构。也就是说,编译器如何知道[在一次传递中]如果没有
struct node
的完整定义,为
struct node
分配多少空间?您的定义存在多个排序问题。(例如)您尝试在定义
struct node
之前在
struct node
内部实例化
union nvalue
。将
union nvalue放入{
结构节点{
行之前。对于您正在定义的几乎所有内容,都是如此。您必须先“定义”它,然后才能“使用它”。