C语言 C11:匿名结构的Typedef与指向Typedef的指针作为成员一起工作?



我通常是这样在C语言中为链表定义Node的:

typedef struct _Node {
    int value;
    struct _Node * next;
} Node;
通过一些测试,我发现我能够通过一个匿名结构体使这个定义工作,像这样:
typedef struct {
    int value;
    struct Node * next;
} Node;

是否有一个原因,为什么这工作?我觉得它不应该工作,因为Node在结构定义中还不是一个类型。

我的假设是结构Node * next是一个匿名结构本身,只有一个指向Node的指针。但如果是这种情况,那么我如何能够使用这里的节点类型,如果类型定义尚未解决?

这似乎只是工作。"tag"名称空间和"普通标识符"的名称空间;在C中是完全不同的(c++的规则略有不同)

匿名struct的成员next指向由同一声明前向声明的不完整struct Node

您的typedef命名了一个匿名的struct,它与struct Node类型不同。所以你的指针next指向一个编译器只知道它是struct的类型。

避免这种头痛的一个好策略是将struct Nodetypedef转发声明为相同的:

typedef struct Node Node;
               ^^^^ ^^^^
               tag  typedef name

struct Node {
  ...
};

此声明

typedef struct {
    int value;
    struct Node * next;
} Node;

引入了两个结构说明符。第一个是未命名的结构体,其类型定义名为Node。第二个是命名结构体struct Node

这两个结构说明符不同。

例如,当你试图将Node *类型的指针赋值给struct Node *类型的指针时,编译器会发出警告或错误,反之亦然,因为存在使用不兼容的指针类型。

考虑下面的演示程序。

#include <stdlib.h>
#include <stdio.h>
typedef struct {
    int value;
    struct Node * next;
} Node;
int main( void )
{
    Node *head = malloc( sizeof( Node ) );
    head->value = 1;
    head->next = NULL;
    Node *next = malloc( sizeof( Node ) );
    next->value = 2;
    next->next = NULL;
    head->next = next;
}

对于语句

head->next = next;

,例如编译器GCC 11.2会发出以下警告

<source>:18:16: warning: assignment to 'struct Node *' from incompatible pointer type 'Node *' [-Wincompatible-pointer-types]
   18 |     head->next = next;
      |                ^
ASM generation compiler returned: 0
<source>: In function 'main':
<source>:18:16: warning: assignment to 'struct Node *' from incompatible pointer type 'Node *' [-Wincompatible-pointer-types]
   18 |     head->next = next;
      |               

此外,您将无法解引用类型为struct Node *的指针,因为struct Node类型是不完整类型。struct Node的定义是未知的。

例如,如果您将在上面的演示程序后面加上语句

printf( "%dn", head->next->value );

编译器此时将发出以下错误消息

<source>:21:31: error: invalid use of undefined type 'struct Node'
   21 |     printf( "%dn", head->next->value );
      |                               ^~

你可以写成

typedef struct Node Node;
struct Node {
    int value;
    Node * next;
};

最新更新