Typedef,标记和未标记的结构以及不兼容的指针类型

请考虑以下C代码段:

typedef struct node{ int val; struct node* left; struct node* right; }node; void inorderTraversal(node *p){ inorderTraversal(p->left); printf("%d",p->val); inorderTraversal(p->right); } 

如果我只编写typedef struct而不是typedef struct node ,当我在main()调用inorderTraversal(root)时,我会收到一条警告,说“传递不兼容指针类型的参数”。 为什么即使程序没有显示任何错误,我也会收到此警告?

如果您没有为结构提供标记名称,

 struct node* left; 

在struct定义中声明一个新的(不完整的)类型struct node 。 因此,当您将指针传递给期望node*那个(不完整)类型时,您将传递一个不兼容类型的指针。

当您定义的结构具有指向同一类型的指针的成员时,您必须能够在定义中命名该类型,因此该类型必须在范围内。

如果给struct命名,那么类型是 – 从那时开始 – 在范围内,并且可以作为struct node (如果标记是node )引用(尽管尚未完成)。 在typedef完成之后,可以将类型称为struct nodenode ,无论您喜欢哪个。

但是如果你没有给struct一个标签,那么在typedef完成之前,类型是匿名的,并且在此之前不能以任何方式引用。 而且从那时起

 struct node *left; 

如果遇到struct node引用的类型,则该行声明一个新类型struct node ,其中没有任何已知的类型。 编译器没有理由将该类型与当前正在定义的类型连接。 所以在那时, struct包含一个成员,该成员是指向未知不完整类型的指针。 现在,在inorderTraversal ,当你打电话时

 inorderTraversal(p->left); 

对于node *p ,通过node的定义, p->left是指向未知不完整类型struct node的指针。 如果已经创建了p->left使得p->left实际上是指向node的指针,那么事情仍然可以工作(除了可能在指向不同类型的指针具有不同表示的平台上),但是你将指针传递给指针的一种类型预期到不同的类型。 由于一种类型不完整,因此与预期类型不兼容。

 "passing argument of incompatible pointer type" 

因为那时节点是未知的。 所以它被认为是一种新型。

 struct node{ int val; struct node* left; struct node* right; }; void inorderTraversal(struct node *p){ inorderTraversal(p->left); printf("%d",p->val); inorderTraversal(p->right); } 

现在,node在使用之前被声明为struct。 即struct node* left; 所以没有错误。

请参考这个: 自引用结构定义?
指向自我的C结构

您无法创建匿名typedef ,它必须具有名称。 C不支持匿名struct类型。

GCC扩展将启用该function: -fms-extensions