简体   繁体   中英

C11: Typedef of an anonymous struct works with pointers to the typedef as a member?

Here is how I would usually define a Node for a linked list in C:

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

With some testing, I have found that I am able to get this definition to work via an anonymous struct, like this:

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

Is there a reason why this works? I feel like it shouldn't work since Node isn't a type yet in the struct definition.

My hypothesis is that the struct Node * next is an anonymous struct itself that only has a pointer to a Node. But if this is the case then how am I able to use the Node type here if the typedef isn't resolved yet?

This only seems to work. The "tag" name space and the name space of "ordinary identifiers" are completely distinct in C. (C++ has slightly different rules)

Your member next of the anonymous struct points to an incomplete struct Node that is forward-declared by that same declaration.

Your typedef names an anonymous struct that is distinct from that type struct Node . So your pointer next points to a type for which the compiler knows nothing more than that it is a struct .

A good strategy to avoid such headaches is to forward declare struct Node and the typedef to be the same:

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

and then

struct Node {
  ...
};

This declaration

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

introduces two structure specifiers. The first one is the unnamed structure with the typedef name Node . The second one is the named structure struct Node .

These two structure specifiers are different.

So for example the compiler will issue a warning or an error when you will try to assign a pointer of the type Node * to a pointer of the type struct Node * or vice versa because there are used incompatible pointer types.

Consider the following demonstration program.

#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;
}

For the statement

head->next = next;

for example the compiler gcc 11.2 issues the following warnings

<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;
      |               

Moreover you will be unable to dereference a pointer of the type struct Node * because the type struct Node is an incomplete type. The definition of struct Node is unknown.

For example if you will append the above demonstration program with statement

printf( "%d\n", head->next->value );

then the compiler at this time will issue the following error message

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

Instead you could write for example

typedef struct Node Node;

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM