当T不是现有类型时,为什么编译“struct T * next”?

时间:2013-03-20 05:23:03

标签: c pointers gcc struct

我在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,而是指一般性谈话)

4 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:3)

编译器将接受代码,例如:

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的成员,就需要包含定义它的头文件。

答案 2 :(得分:0)

这取决于你的意思是“不存在”。如果您甚至没有宣布 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;

答案 3 :(得分:0)

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

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