C语言中的相互依赖结构
我正在关注Ruslan Spivak的文章系列/教程“让我们构建一个简单的解释器”,这是一个用Python构建简单Pascal解释器的指南。我正试图学习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; };
#包括“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放入{
在结构节点{
行之前。对于您正在定义的几乎所有内容,都是如此。您必须先“定义”它,然后才能“使用它”。