C中的类型声明(概念)

C中的类型声明(概念),c,struct,type-declaration,C,Struct,Type Declaration,一般来说,这个问题更多的是一个概念问题,而不是本质上的编码问题。当我偶然发现这些代码时,我很好奇它们是否有效。或者基本上为什么,如果有人能给我一个解释的话 以下是C中的一些类型声明: typedef struct Rec1 * Ptr1; typedef struct Rec2 * Ptr2; struct Rec1 { int data; Ptr2 next; }; struct Rec2 { double data; Ptr2 next; }; 这些应该

一般来说,这个问题更多的是一个概念问题,而不是本质上的编码问题。当我偶然发现这些代码时,我很好奇它们是否有效。或者基本上为什么,如果有人能给我一个解释的话

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

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

struct Rec1
{
    int data;
    Ptr2 next;
};

struct Rec2
{
    double data;
    Ptr2 next;
};
这些应该被允许吗?允许吗?为什么

它们有效吗

是的,它们是有效的 原因:

  • 前两行创建
    Ptr1
    Ptr2
    作为
    struct Rec1*
    struct Rec2*
    的类型定义

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

  • 他们应该被允许吗

    您还可以如何创建自引用结构

    它们有效吗

    是的,它们是有效的 原因:

  • 前两行创建
    Ptr1
    Ptr2
    作为
    struct Rec1*
    struct Rec2*
    的类型定义

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

  • 他们应该被允许吗

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

    简短版本:

    • 应该允许吗?对

    • 它们是(转发类型定义)吗?对

    • 为什么

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

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

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

    简短版本:

    • 应该允许吗?对

    • 它们是(转发类型定义)吗?对

    • 为什么

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

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


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

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


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

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


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

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

    现在,如果你问这一切是如何运作的,很简单

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

    因此,
    Ptr2
    只是一种预先已知大小的指针类型(如果CPU的地址空间为0到4 GB,则32位地址足以寻址每个字节,32位将是此CPU上的本机指针大小)您可以在
    struct Rec1
    struct Rec2
    中为这样一个指针分配空间,即使这个指针指向的东西还不知道,这就是我们在讨论中的代码
    Ptr1
    Ptr2
    被定义为不完整类型,这是它的正式名称

    在语言中实现这种不完整指针类型的基本原理非常实用。如果要创建链接列表或树,它们的元素或节点必须以某种方式指向与之链接的其他元素或节点。理论上,您可以为最后一个元素(或叶节点)创建不同的元素/节点类型,然后为指向它的元素/节点类型,然后为指向该元素的元素/节点类型,依此类推。但是,如果您的元素或节点不止几个,那么这就不能很好地扩展。如果你想要一百万呢?定义一百万个几乎相同的类型充其量是不切实际的。因此,语言为您提供了避免这种情况的捷径。您还可以将
    next
    指针声明为
    void*
    指针,但是您需要将它们到处强制转换为
    struct Rect1*
    s