【问题标题】:Why does "struct T* next" compile when T isn't an existing type?当 T 不是现有类型时,为什么“struct T* next”会编译?
【发布时间】:2013-03-20 05:23:02
【问题描述】:

我在 Windows 上使用 MinGW。我正在构建链表,对此我感到困惑。

#include <stdio.h>
#include <stdlib.h>

typedef struct Data
{
    int x;
    int y;
    struct BlaBla * next;               /*compiles with no problem*/
}List;

int main(void)
{
    List item;
    List * head;
    head = NULL;
    return 0;
}

我现在该结构不能具有结构变量(对象,该结构的实例),但可以具有该结构类型的指针。不知道指针可以是不存在类型的指针。 struct BlaBla * next;(不是链表,必须是struct Data * next,但意思是泛泛之谈)

【问题讨论】:

  • 我相信这些被称为“不完整类型”。
  • struct BlaBla 必须在您的程序中的某个地方定义...它编译是因为它将其视为用户定义的类型并且没有进一步定义......但是当您尝试使用它时你的程序它会给你错误,因为它无法找到 struct blabla 的成员。
  • @KinjalPatel 它will compile.

标签: c pointers gcc struct


【解决方案1】:

是的,您可以,因为编译器在第一次遇到未知类型名称时,会假定存在 somehwere 具有此名称的结构类型定义。然后它会为你forward-declare结构名称,让你把它当作一个指针使用,但是你不能取消引用它也不能对它进行指针运算(因为它是一个不完整的类型)。

【讨论】:

    【解决方案2】:

    编译器将接受例如您的示例的代码:

    typedef struct Data
    {
        int x;
        int y;
        struct BlaBla * next;               /*compiles with no problem*/
    }List;
    

    这没关系,因为编译器知道指针的大小,并且编译器假设结构将在取消引用之前定义。

    因为编译器是这样操作的,所以可以这样做:

    typedef struct Data
    {
        int x;
        int y;
        struct Data * next;     /* points to itself */
    } List;
    

    但是,如果您要包含内联结构,如下所示:

    typedef struct Data
    {
        int x;
        int y;
        struct BlaBla blaStruct;               /* Not a pointer. Won't compile. */
    }List;
    

    编译器无法计算出struct Data 有多大,因为它不知道struct BlaBla 有多大。要编译它,您需要包含struct BlaBla 的定义。

    请注意,只要您需要访问struct BlaBla 的成员,您就需要包含定义它的头文件。

    【讨论】:

      【解决方案3】:

      这取决于您所说的“不存在”是什么意思。如果你还没有声明BlaBla,你会得到一个错误。

      如果你已经声明了它但还没有定义它,那会很好用。您可以拥有指向不完整类型的指针。

      事实上,这是在 C 中做opaque pointers 的正常方式。

      因此,您可能认为这是无效的,因为范围内没有 struct BlaBla 的声明:

      typedef struct Data {
          struct BlaBla *next;  // What the ??
      } List;
      

      不过,实际上没关系,因为它同时声明了struct BlaBla 和定义next。

      当然,既然定义就意味着声明,这也是可以的:

      struct BlaBla { int xyzzy; };
      typedef struct Data {
          struct BlaBla *next;  // What the ??
      } List;
      

      【讨论】:

      • 好吧,我绝不是 C 标准专家,我不敢质疑你,但如果我在 this code 上运行 clang -Wall -std=c99 -pedantic,我什至不会收到警告。跨度>
      • struct BlaBla *next; 声明了 stuct BlaBla 和成员 next——即使之前从未声明过 struct BlaBla 也不是错误。
      【解决方案4】:

      为了声明一个给定类型的变量或字段,将一个作为参数传递,或者将一个复制到另一个相同类型,编译器必须知道变量或字段占用多少字节,它有什么对齐要求有(如果有的话),以及它兼容的其他指针类型,但这就是编译器需要知道的全部。在 C 的所有常见方言中,指向任何结构的指针将始终具有相同的大小并需要相同的对齐方式,而不管它指向的结构的大小或该结构可能包含的内容,并且指向任何结构类型的指针仅与指向相同结构类型的其他指针兼容。

      因此,代码不需要对指向结构的指针做任何事情,除了分配空间来保存指针本身[与它们指向的结构相反]、将它们作为参数传递或将它们复制到其他指针,除了其唯一名称之外,不需要知道它们指向的结构类型的任何信息。需要为结构分配空间(而不是指向结构的指针)或访问其任何成员的代码必须更多地了解其类型,但不做这些事情的代码不需要此类信息。

      【讨论】:

        猜你喜欢
        • 2015-04-24
        • 1970-01-01
        • 2015-07-23
        • 1970-01-01
        • 2021-02-08
        • 1970-01-01
        • 2016-07-02
        • 2015-02-27
        • 1970-01-01
        相关资源
        最近更新 更多