In C, most of the code declaring structs will follow this pattern:
/* struct forward-declaration */
typedef struct T T ;
/* struct definition */
typedef struct T
{
/* etc. */
} T ;
This is so prevalent most developers I talked with didn't even know the code above did two things at the same time (struct declaration, then aliasing the struct name in the normal namespace), and just wrote it out of habit.
In C++, the issue is mitigated so you can omit the typedefing part. In C# and in Java, the designers didn't even bother. So those languages won't help understand why C does this that way.
So, after Oliver Charlesworth's suggestion:
Is there a technical reason to have struct T
in a separate namespace from other normal identifiers?
The relevant section in the C89/C90 standard is:
6.1.2.3 Name spaces of identifiers
It more than one declaration of a particular identifier is visible at any point in a translation unit. the syntactic context disambiguates uses that refer to different entities. Thus. there are separate name spaces for various categories of identifiers, as follows:
[...]
the tags of structure, unions and enumerations (disambiguated by following any of the keywords struct, union, or enum).
[...]
all other identifiers. called ordinary identifiers (declared in ordinary declarators or as enumeration constants).
The text for C11 (n1570:6.2.3 standard draft) is more or less the same.
A struct (or class) that has only static data and methods is not so different from a namespace. But with a struct that has non-static data, you can create different objects with different data.
Using Declarations. Using directives make all namespace members accessible without qualification. In contrast, using declarations qualify only individual namespace members. Using declarations are declarations and, as such, create declarations in the current scope.
Syntax. Using typedef struct results in a cleaner, more readable code, and saves the programmer keystrokes. However, it also leads to a more cluttered global namespace which can be problematic for large programs.
C has four different name spaces for identifiers: Label names (the goto type). Tags (names of structures, unions and enumerations). Members of structures and unions (these have a separate namespace per structure/union). All other identifiers (function names, object names, type(def) names, enumeration constants, etc).
Until typedef
was added to complicate parsing, object declarations would always start with a reserved word: struct
, int
, char
, float
, or double
, and maybe long
or union
(not sure whether those were added before or after typedef
). Since structure tags couldn't appear anywhere except after the keyword struct
, there was no reason for a compiler to care if a structure tag shared a name with any other identifier.
The need to have typedef
names be distinct from those of any other identifiers is a result of grammatical ambiguity created by allowing custom types to be used in object declarations or cast expressions without any reserved words or punctuators (at the start of a function, x * y;
could either create an object named y
of type x*
, or could multiply x
by y
and discard the result, and (x)(y)
could either cast y
to type x
or invoke function x
with argument y
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With