《The C programming language, second edition》的 section A8.3 中,有这么一段话:

A structure may not contain a member of incomplete type. Therefore, it is impossible to declare a structure or union containing an instance of itself. However, besides giving a name to the structure or union type, tags allow definition of self-referential structures; a structure or union may contain a pointer to an instance of itself, because pointers to incomplete types may be declared.

我对 it is impossible to declare a structure or union containing an instance of itself. 百思不得其解,因此探索了一番。

原因(中文)

在 C 编程中,不可能直接声明一个包含自身实例的结构体或联合体。这个限制被称为"自引用"或"递归"声明,与内存分配和结构体大小确定的方式有关。

当声明一个结构体或联合体时,编译器需要知道结构体的大小以便为其分配内存。然而,如果一个结构体包含自身的实例,结构体的大小就变得不确定,无法确定。

我们来举个例子来说明这个问题:

1
2
3
4
struct Node {
    int data;
    struct Node next;  // 错误的声明:结构体包含自身实例
};

在上面的例子中,定义了一个 Node 结构体,其中包含了同样是 Node 结构体类型的成员 next。问题在于编译器无法确定 Node 的大小,因为它取决于 next 的大小,而 next 又是一个 Node 结构体。这就形成了递归定义,导致结构体的大小变得无限大。

为了解决这个限制,可以使用指针来实现自引用的行为。以下是一个更新后的示例:

1
2
3
4
struct Node {
    int data;
    struct Node* next;  // 正确的声明:使用结构体的指针
};

在这个修改后的示例中,next 成员被声明为指向 Node 结构体的指针(struct Node*),而不是直接嵌套一个结构体实例。指针的大小是固定的,不管它指向的类型是什么,因此可以正确确定结构体的大小。

通过使用指针,可以创建链式结构或递归数据结构,其中每个节点指向另一个节点,从而实现更灵活和动态的内存分配。

总结起来,在C语言中无法直接声明包含自身实例的结构体或联合体,是因为难以确定这种结构体的大小。但是,可以使用指针来实现类似的自引用行为,创建递归或链式数据结构。

answer

In C programming, it is not possible to declare a structure or union that contains an instance of itself directly. This limitation is known as “self-referential” or “recursive” declaration, and it is related to the way memory is allocated and the size of the structure is determined.

When a structure or union is declared, the compiler needs to know the size of the structure in order to allocate memory for it. However, if a structure contains an instance of itself, the size of the structure becomes indefinite and cannot be determined.

Let’s take an example to illustrate this issue:

1
2
3
4
struct Node {
    int data;
    struct Node next;  // Incorrect declaration: structure contains an instance of itself
};

In the above example, the Node structure is defined with a member next of the same structure type Node. The problem here is that the compiler cannot determine the size of Node because it depends on the size of next, which is itself a Node structure. This creates a recursive definition and leads to an infinite size for the structure.

To overcome this limitation, you can use pointers to achieve self-referential behavior. Here’s an updated example:

1
2
3
4
struct Node {
    int data;
    struct Node* next;  // Correct declaration: using a pointer to the structure
};

In this modified example, the next member is declared as a pointer to the Node structure (struct Node*), rather than directly embedding an instance of the structure. Pointers have a fixed size, regardless of the type they are pointing to, so the size of the structure can be determined correctly.

By using pointers, you can create linked structures or recursive data structures where each node points to another node, allowing for more flexible and dynamic memory allocation.

In summary, the inability to declare a structure or union containing an instance of itself directly in C is due to the challenge of determining the size of such a structure. However, you can use pointers to achieve similar self-referential behavior and create recursive or linked data structures.