为什么在自引用结构体中要使用指针?

3

为什么在自引用结构中使用指针?这是强制的吗?如果不是,相对于普通结构定义,拥有指向结构体的指针有什么优势?

typedef struct _Struct {
  struct _Struct* next;  // do we really need this pointer?
} Struct;

8
如果一个结构体包含了其自身的一个实例,那么这个结构体的大小就是无限大。 - user3386109
@user3386109 只有包含至少一个附加字段时才需要这样做。否则,它将成为一个无限嵌套的结构,其终端字段将无法访问。 - Tom Karzes
成员变量 next 对于“自引用结构体”来说是一个奇怪的名称。也许您可以发布一下使用 struct _Struct 的上下文。我认为您实际看到的上下文是链表。 - chux - Reinstate Monica
3个回答

6

指针有固定大小,因此编译器在解析_Struct时可以确定结构体的大小。

如果_Struct包含自身,则无法确定其大小,这是一个循环定义。


1
那么,没有指针就无法使用它了吗? - Anton Barinov
1
@AntonBarinov: 如果_Struct包含_Struct和一个32位整数,它的大小将为4字节+_Struct。但现在它是8字节。不,等等,12字节,16字节,等等...这就是为什么必须使用固定大小的指针。 - Zan Lynx
3
一个 C 结构的成员在物理上是结构的一部分,占用了与定义为单独变量相同的内存空间。一个结构体不能包含其自身的实例。(你可能已经习惯了其他语言,在其他语言中,一个结构体的结构成员会被实现为隐式引用。但是C语言不会这样做。) - Keith Thompson
@ZanLynx 非常感谢。 - Anton Barinov
感谢大家的解释。 - Anton Barinov

3

包含外部结构的实例成员在结构中是没有意义的。除了需要声明不完整类型之外,它将是无限的,并且永远不会有足够的字节,因为每个添加的实例都将需要一个实例。

使用指针则没有问题; 例如,这种方法常用于创建链表。指针指向链中的下一个实例。


2
在结构定义中,您不能使用结构类型成员变量struct _Struct,因为它必须是完整的类型才能这样做。但是,在声明中遇到}之前struct _Struct不是完整的。
但是对于指针可以这样做,因为指针的大小无论是完整类型还是不完整类型都是相同的,所以编译器在读取它们时可以决定它的大小(与它引用自身的情况不同)。
它必须是指向结构本身的指针,而不是结构本身,因为类型尚未完成 - 不知道它的大小是多少。
支持我所说的话-来自标准§6.7.2.1p3

结构或联合 不得包含不完整或函数类型的成员 (因此,结构不得包含其实例,但可以包含指向其实例的指针),除非具有一个以上命名成员的结构的最后一个成员具有不完整数组类型;这样的结构(以及任何包含可能递归地包含此类结构的成员的联合)不得是结构的成员或数组的元素。

另外,何时才算完成?来自§6.7.2.1p8

在结构体或联合体说明符中存在struct-declaration-list会声明一个新类型,它是翻译单元内的类型。struct-declaration-list 是一系列用于结构体或联合体成员的声明。如果 struct-declaration-list 不包含任何具名成员,无论是直接还是通过匿名结构体或匿名联合体,行为未定义。该类型在终止列表的}之后立即变为不完整,此后变为完整。

如果有人问什么是不完整类型的结构或联合?来自标准§6.2.5p22

未知内容的结构体或联合体类型(如6.7.2.3中所描述)是不完整的类型。

这就是为什么我们不能使用正在声明的结构的实例 - 因为简单地说,它的大小无法知道。

1
顺便提一句,这是一个很好的回答 - 很好地解释了struct _Struct,因为其成员仍然是不完整的。 - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接