Introduction
If you have programmed in C you have probably seen code that insists on writing struct before a structure type name every time you declare a variable. For example, programmers write struct point p; rather than just point p;. This requirement often feels odd compared to other languages where type names are used directly. This article explains the technical, historical, and practical reasons why C requires the struct keyword to reference structure types.
Technical reason: separate tags namespace
The core language reason is that C maintains a separate namespace for structure, union, and enumeration tags. In C terminology a structure name like point is a tag, not an ordinary type identifier. The compiler therefore requires the struct keyword to tell it to look in the tags namespace. This design allows the same identifier to be used for two different things, for example a structure tag and a function or variable name with the same spelling.
Practical example and POSIX context
Using separate namespaces enables patterns that are common in C code and in system interfaces. For example, POSIX defines a type called stat. Because of the tags namespace you will often see struct stat used to refer to the structure type while other symbols or functions can also be named stat. Requiring the struct keyword avoids name collisions and keeps the meaning unambiguous for the compiler.
Historical and language-design background
C inherited its syntax and many ideas from predecessors and from the constraints of early C evolutions. Early designers prioritized a small, explicit syntax. The separate tags namespace predates widespread use of typedef aliases and was a deliberate choice to let programmers reuse identifiers in different roles. Later languages such as C++ changed this design. Bjarne Stroustrup removed the need to repeat keywords so that user defined types could behave more like built-in types. In C++ class and struct names are ordinary type names after declaration, which is why C++ code can write point p; if point is a declared class or struct.
Workarounds in C: typedef and common idioms
C programmers use idioms to reduce verbosity while keeping compatibility. The most common pattern is to introduce a typedef alias so the tag is not required every time:
- typedef struct point { int x, y; } point; This lets you write point p; afterwards.
- typedef struct node node; combined with a forward declaration struct node; is another pattern that helps with recursive types.
These typedefs provide convenience but are not magic. They simply introduce a new identifier in the ordinary identifier namespace that aliases the tag type.
Forward declaration and pointers
The separate tags namespace enables useful forward declarations. You can write struct node; before the full definition and then declare pointers such as struct node *next; inside other structures. This is essential for implementing linked lists, trees, and other recursive data structures without exposing the complete layout immediately.
Pros and cons of C design
- Pros: avoids name collisions between tags and ordinary identifiers, supports lightweight forward declarations, preserves backward compatibility and simple compiler lookup rules.
- Cons: requires repeating struct unless you add a typedef, can feel verbose compared to modern languages, and is an extra cognitive detail for newcomers.
Best practices
For API code and public headers choose explicit names and consider typedefs for user-facing types so callers do not have to write struct repeatedly. For internal code prefer whichever style your codebase uses consistently. Always use forward declarations for recursive types and declare typedefs where they improve clarity.
Summary
C requires the struct keyword because structure tags live in a separate namespace from ordinary identifiers. This design choice has historical roots and practical benefits such as avoiding name collisions and enabling forward declarations. If you prefer the brevity of using type names directly, the standard C workaround is to create a typedef alias. Understanding this behavior helps you read and write robust C code and explains why C differs from languages that merged these namespaces.

Leave a Reply