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?
CodePudding user response:
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 {
...
};
CodePudding user response:
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;
};