Very early versions of C (before the first edition of K&R was published in 1978) did not have the typedef
feature. In that version of C, a type name could always be recognized syntactically. int
, float
, char
, struct
, and so forth are keywords; other elements of a type name are punctuation symbols such as *
and []
. (Parsers can distinguish between keywords and identifiers that are not keywords, since there are only a small and fixed number of them.)
When typedef
was added, it had to be shoehorned into the existing language. A typedef
creates a new name for an existing type. That name is a single identifier -- which is not syntactically different from any other ordinary identifier.
A C compiler must maintain a symbol table as it parses its input. When it encounters an identifier, it needs to consult the symbol table to determine whether that it's a type name. Without that information, the grammar is ambiguous.
In a sense, a typedef
declaration can be thought of as creating a new temporary keyword. But they're keywords that can be hidden by new declarations in inner scopes.
For example:
{
typedef short g;
/* g is now a type name, and the parser has
* to treat it almost like a keyword
*/
{
int g;
/* now g is an ordinary identifier as far as the parser is concerned */
}
/* And now g is a type name again */
}
Parsing C is hard.