Reputation: 31459
Consider this code:
typedef struct _Node Node;
struct _Node {
struct _Node * node;
};
or this:
typedef struct _Node {
struct _Node * node;
} Node;
Is there any reason at all to not rewrite them to
typedef struct Node Node;
struct Node {
Node * node;
};
and
typedef struct Node {
Node * node;
} Node;
As far as I can see they are equivalent. What is the reason for those underscore prefixes? I have also seen other variants, where it's not an underscore, but instead a capital letter on the first occurrence and lowercase on the second, or something else that makes them different. One example is here:
typedef struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
} Book;
This example comes from tutorialspoint and I know that they in general should not be considered a reliable source. But is there any good reason to do like this?
Upvotes: 3
Views: 412
Reputation: 755064
People use names like struct _Node
to willfully ignore the rules set in the standard (or, more frequently, because they're unaware of the rules set in the standard). Roughly, the standard says that names starting with an underscore are mostly reserved for 'the implementation', meaning the compiler and the system libraries. See C11 §7.1.3 Reserved identifiers for the details:
- All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
- All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
Also note §6.2.1 Scopes of identifiers — emphasis added:
An identifier can denote an object; a function; a tag or a member of a structure, union, or enumeration; a typedef name; a label name; a macro name; or a macro parameter. The same identifier can denote different entities at different points in the program. A member of an enumeration is called an enumeration constant. Macro names and macro parameters are not considered further here, because prior to the semantic phase of program translation any occurrences of macro names in the source file are replaced by the preprocessing token sequences that constitute their macro definitions.
Note too that POSIX reserves the _t
suffix too — see The Compilation Environment.
That said, the thought process seems to be "this name shouldn't be used much; prefix it with an underscore to discourage its use". And also "I've seen it used in system headers; I'll copy that style", not realizing that the system headers are coded that way to avoid treading on the namespace reserved for ordinary programmers and to use the namespace reserved for the implementation.
Your rewrite is sensible; it's what I normally do.
To address the expanded question:
Not everyone is aware that structure tags are in a separate namespace from ordinary identifiers, so they aren't aware that typedef struct Book Book;
is completely safe and unambiguous (the first Book
is in the tag name space and must be preceded by struct
; the second Book
is in the ordinary identifiers name space and must not be preceded by struct
).
Also, people look at system headers and see what they do and think they should copy the style there, without being aware that the implementation has different rules imposed upon it about what it can and cannot use for names.
Note that the Linux kernel coding standards discourage the use of typedefs for structure types; they require you to use struct WhatEver
everywhere. There some advantages and some disadvantages to the rule — self-consistency is probably more important than which convention you use. That means 'go with the flow' for an existing project, but it doesn't matter too much which way you do it on a new project of your own, as long as you're consistent.
You can also find precedent for using alternative names for structure tags and the corresponding typedef names in the holy scripture — meaning "The C Programming Language" by Kernighan and Ritchie. (Interestingly, their examples changed quite a bit between the 1978 first edition and 1988 second edition.)
Second edition:
typedef struct tnode *Treeptr;
typedef struct tnode {
…
Treeptr left;
Treeptr right;
} Treenode;
First edition:
typedef struct tnode {
…
struct tnode *left;
struct tnode *right;
} TREENODE, *TREEPTR;
Note that modern style tends to avoid using typedef for pointers. See Is it a good idea to typedef pointers?.
Upvotes: 5