这个问题通常更像是一个概念性问题而不是编码问题。当我遇到这些代码并且想知道它们是否有效时,我很好奇。或者为什么基本上,如果有人可以给我一个解释呢?
以下是C:
中的一些类型声明typedef struct Rec1 * Ptr1;
typedef struct Rec2 * Ptr2;
struct Rec1
{
int data;
Ptr2 next;
};
struct Rec2
{
double data;
Ptr2 next;
};
这些是否应该被允许?他们被允许吗?为什么或为什么不呢?
答案 0 :(得分:3)
它们有效吗?
原因:
前两行创建Ptr1
和Ptr2
作为struct Rec1 *
和struct Rec2 *
的类型定义。
由于它们是指针,而不是结构本身,它们使struct Rec1
和struct Rec2
成为不完整的类型,它们只是将Rec2
作为递归类型(通常使用)在创建数据结构时)和Rec1
具有指向Rec2
对象的指针。
他们应该被允许吗?
您还可以创建自引用结构吗?
答案 1 :(得分:1)
简短版本:
应该允许吗?是
是(转发类型定义)吗?是
为什么或为什么不呢?
这是一种普遍接受的转发类型声明方式。它允许声明一个不完整的类型并在以后定义它。在这种简单的情况下,这不是什么大问题,但在更复杂的情况下绝对是必要的。
Linux或Darwin内核都相当广泛地使用这种技术以允许在其自己的头文件中定义数据类型的方式声明内部内核结构,但允许在完全定义之前使用数据类型。
如果没有这种机制,复杂,相互依赖,数据类型的定义将是不可能的。
答案 2 :(得分:1)
根据语言标准,它们是有效的,因此应该被允许。
现在,如果你问这一切是如何运作的,那就很容易了。
指针通常只是内存地址。如果对象由整数个字节(每个字节都有唯一的地址)表示,则可以指向内存中的任何对象。我在这里说“积分”是因为你不能有一个指向结构位字段的指针(至少,你不能指向那些不在字节边界上开始并占用整数字节的指针)
因此,Ptr2
只是一个预先知道大小的指针类型(如果你的CPU的地址空间是0到4 GB,32位地址足以解决每个字节,32位将是本机这个CPU上的指针大小)你可以在struct Rec1
和struct Rec2
中为这样的指针分配空间,即使这个指针指向的东西还不知道,这就是我们在有问题的代码中所拥有的。 Ptr1
和Ptr2
被定义为不完整类型,这是此的正式名称。
在语言中实现此类不完整指针类型的基本原理非常实用。如果要创建链接列表或树,则它们的元素或节点必须以某种方式指向与其链接的其他元素或节点。理论上,您可以为最后一个元素(或叶子节点)创建不同的元素/节点类型,然后为指向它的那个创建不同的元素/节点类型,然后为指向该元素的那个创建不同的元素/节点类型,依此类推。但是,如果你不仅仅有一些元素或节点,那么它的扩展性也不会很好。如果你想要一百万个怎么办?定义一百万种几乎相同的类型是不切实际的。因此,该语言为您提供了一个捷径,以避免这种情况。您还可以将next
指针声明为void*
指针,但是您需要将它们转发到struct Rect1*
或struct Rect2*
,并且维护和调试此类代码是容易出错。所以,在那里,语言为你提供了帮助。
答案 3 :(得分:0)
typedef只是它引用的实际类型的别名。您可以将其视为宏,但它不是在编译的预处理阶段被替换的东西。
用 struct Rec1 * 代替所有出现的 Ptr1 会产生一个有效的代码,这是确认代码是否有效的最简单方法;)