0

这个问题通常更多是一个概念问题,而不是本质上的编码问题。当我遇到这些代码时,我很好奇,想知道它们是否有效。或者为什么基本上,如果有人可以给我一个解释?

以下是 C 中的一些类型声明:

typedef struct Rec1 * Ptr1;
typedef struct Rec2 * Ptr2;

struct Rec1
{
    int data;
    Ptr2 next;
};

struct Rec2
{
    double data;
    Ptr2 next;
};

这些应该被允许吗?他们被允许吗?为什么或者为什么不?

4

4 回答 4

3

它们有效吗?

是的,它们是有效的

原因:

  1. 前两行创建Ptr1andPtr2作为 astruct Rec1 *和的类型定义struct Rec2 *

  2. 由于它们是指针,而不是结构本身,因此它们将struct Rec1andstruct Rec2作为不完整的类型,并且它们只是Rec2作为递归类型(通常用于创建数据结构)并Rec1具有指向Rec2对象的指针。

他们应该被允许吗?

您还能如何创建自引用结构?

于 2013-02-26T02:37:55.093 回答
1

根据语言标准,它们是有效的,因此应该被允许。

现在,如果你问这一切是如何运作的,这很容易。

通常,指针只是内存地址。如果对象由整数字节表示(每个字节都有唯一的地址),则您可以拥有指向内存中任何对象的指针。我在这里说“整数”是因为你不能有一个指向结构位字段的指针(至少,你不能有一个指向那些不在字节边界开始并占据整数字节的指针) .

因此,Ptr2它只是一个预先知道大小的指针类型(如果您的 CPU 的地址空间是从 0 到 4 GB,则 32 位地址足以寻址每个字节,而 32 位将是该 CPU 上的本机指针大小)并且您可以为这样的指针分配空间,struct Rec1即使struct Rec2该指针指向的内容尚不知道,这就是我们在相关代码中所拥有的。Ptr1并且Ptr2被定义为不完整的类型,这是它的正式名称。

在语言中实现这种不完整指针类型的基本原理是非常实用的。如果要创建链接列表或树,它们的元素或节点必须以某种方式指向与它们链接的其他元素或节点。理论上,您可以为最后一个元素(或叶节点)创建不同的元素/节点类型,然后为指向它的元素创建不同的元素/节点类型,然后为指向该元素的元素创建不同的元素/节点类型,依此类推。但这不能很好地扩展,如果您有多个元素或节点。如果你想要一百万个呢?定义一百万个几乎相同的类型充其量是不切实际的。因此,该语言为您提供了避免这种情况的捷径。您也可以将next指针声明为只是void*指针,但随后您需要将它们强制转换为struct Rect1*struct Rect2*并且此类代码的维护和调试将容易出错。所以,在那里,语言可以帮助你。

于 2013-02-26T03:16:03.620 回答
1

简短版本:

  • 应该允许吗?是的

  • 它们是(前向类型定义)吗?是的。

  • 为什么或者为什么不?

这是进行前向类型声明的普遍接受的方式。它允许人们声明一个不完整的类型并在以后定义它。在这样的简单情况下这没什么大不了的,但在更复杂的情况下可能是绝对必要的。

Linux 或 Darwin 内核都相当广泛地使用这种技术来声明内部内核结构,这种方式允许在其自己的头文件中定义数据类型,但允许在完全定义之前使用数据类型。

如果没有这种复杂的、相互依赖的机制,数据类型的定义将是不可能的。

于 2013-02-26T02:39:01.410 回答
0

typedef 只是它所引用的实际类型的别名。您可以将其视为宏,但它不是在编译的预处理阶段被替代的东西。

只需将所有出现的Ptr1 替换struct Rec1 * 即可生成有效代码,这是确认代码是否有效的最简单方法;)

于 2013-02-26T02:39:22.037 回答