Is there a technical reason for the "struct namespace" in C?
Asked Answered
H

2

6

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?

Edit

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.

Handgrip answered 30/11, 2014 at 11:34 Comment(12)
Isn't this for typedefs rather than for structs? IOW, what does the typedef change?Thanet
Not 100% clear what you're asking here; is it "why is struct T in a separate namespace from T"?Coffeecolored
Hysterical reasons. Basically, compilers were small and not very smart back when.Teatime
@OliverCharlesworth : You're absolutely right. I updated my question to make it clearer, shamelessly copy-pasting your suggestion. Thanks!.. :-)Handgrip
@Thanet : Try writing C code without the typedef style above, and you'll see in your code, everywhere T is mentioned, it will be qualified with the keyword struct, which can be a bit of a pain. I've never understood the reason.Handgrip
Goes back to very early C, back when even the struct members where in the global namespace. They overshot the fix a bit, perhaps.Ouster
@HansPassant : You should add a full answer on that subject with a bit more information (copy/pasted/adjusted from your other answer, and/or other tidbits)... Because that would be a satisfactory answer for this question, I believe. Is there a document describing this pre-historical C? (e.g., for C++: isocpp.org/blog/2014/10/… )Handgrip
The C99 rationale (6.2.3) says, there had been a lot of variation in implementations. (Which makes sense to me, a separate namespace cannot break existing code relying on either choice, apart from relying on a compiler error.) The same reasoning, however, would apply for having separate namespaces for structure and union tags, so this is not the whole story. Some details about this historic variation would be helpful.Upturned
@paercebal: I think Hans' reasoning is off-topic here (though nonetheless interesting), as this is about the separate name space for tags, not for members. For a document: I don't know of a freely available publication of the first version of K&R TCPL. And I doubt that would be helpful here; variation in implementations may indicate that K&R was vague on this.Upturned
possible duplicate of What is the rationale behind typedef vs struct/union/enum, couldn't there be only one namespace?Polynesia
@JosephQuinsey : I agree. I'll vote for closing the question for being a duplicate. Thanks.Handgrip
That possible duplicate doesn't really ask for separate namespaces, but why structures aren't automatically typedefed. If there was only one namespace, they still weren't, but typedefing them to the structure tag (as in typedef struct foo foo;) would be simply illegal (as foo is redefined in the same scope).Upturned
A
2

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).

Abridge answered 8/9, 2021 at 15:5 Comment(0)
B
0

The first line is only needed if you want to reference struct T using the name T inside the second declaration.

For structs that don't contain such references, only the second form is needed. For such cases, for simplicity and brevity, I would recommend dropping the then pointless struct tag:

typedef struct {
  /* interesting fields go here */
} T;

Also, the typedef doesn't "bring the struct name into the normal namepace", it creates (like typedef always does) an alias (T) for a different type name struct T. Of course there is no connection between the spelling of names here, which is why I recommend dropping tagging the struct in the first place, it just adds a name that is pointless most of the time.

Buzzer answered 30/11, 2014 at 11:55 Comment(2)
Thanks for the answer but... It doesn't answer my question, which was: was there a technical reason to separate the struct types namespace from the from the normal (function and variables) namespace. (See C89/C90 standard, 6.1.2.3 Name spaces of identifiers)Handgrip
Another advantage of the struct tagname form is that one can have a header file define pointers, function parameters, and function return types of such structures without having to worry about whether a complete struct type definition is in scope. If some users of a header would use an importWidget function that expects an argument of type struct Widget*, but others won't, and identifies the type as struct tagName* in that prototype, client code that doesn't use the type won't need to include a definition for it.Abridge

© 2022 - 2024 — McMap. All rights reserved.