Given the following code:
typedef struct elementT {
int data;
struct elementT *next;
} element;
Why is it necessary to do struct elementT *next
and I can't do element *next
inside the struct declaration itself? Is it because it is not declared yet?
The typedef
only takes place after the struct
has been defined. Consider the following code; the syntax is invalid, but it hopes it shows the order/precedence of things:
typedef (struct {
int field1, field2;
}) item;
I.e., the struct{...}
is an "expression" that denotes a type. The typedef
operates on that type by giving it a name.
By contrast,
struct foo {
foo *next;
};
works because of two special rules of C: struct <name>
not only defines a type, but gives it a struct
tag as well, and that tag is immediately visible inside the rest of the struct
declaration (for the obvious reason: linked lists, trees, etc. would be very painful to implement without these rules).
Because C said so:
(C99, 6.2.1p7) "[...] Any other identifier has scope that begins just after the completion of its declarator."
The name elementT
, part of the type name struct elementT
, becomes visible (as an incomplete type) as soon as the compiler sees the two tokens struct elementT
, so you can use it as a type name inside the struct definition.
The name element
, which is a typedef name, doesn't become visible until the identifier element
appears, which is after the end (the closing }
) of the struct definition; thus you can't use it inside the struct definition, simply because it doesn't exist yet.
My own personal preference (and plenty of very smart people differ with me on this point) is not to use typedef
at all. The type already has a perfectly good name, struct ElementT
; why add a second one? I'd just write:
struct element {
int data;
struct element *next;
};
and refer to the type as struct element
.
If you feel that having a single-word name for the type is sufficiently useful, of course, you can still use the typedef. Just remember that the typedef name won't be visible until after the end of the declaration. And there's no need to use two different identifiers:
typedef struct element {
int data;
struct element *next;
} element;
Now you can refer to the type either as struct element
or as element
.
(Note that C++ has different rules; it effectively creates an implicit typedef for a struct
(or union
, class
, or enum
) type. In C++, the typedef
is unnecessary but harmless.)
You can achieve this behaviour if you separate the struct declaration from its definition:
struct ElementT; // not strictly needed
typedef struct ElementT element; // this declares "struct ElementT" as well
struct ElementT
{
element * next;
};