人们使用像
struct _Node
这样的名称,是为了故意忽略标准中设定的规则(或者更经常的是因为他们不知道标准中设定的规则)。大体上,标准规定以下划线开头的名称主要保留给“实现”(即编译器和系统库)。有关详细信息,请参见C11
§7.1.3 保留标识符:
- 任何以下划线和大写字母或另一个下划线开头的标识符都始终保留。
- 任何以下划线开头的标识符都始终保留,用作普通名称空间和标记名称空间中具有文件范围的标识符。
还请注意§6.2.1 标识符的作用域-强调添加:
一个标识符可以表示对象、函数、标签或结构、联合或枚举的成员、typedef名称、标签名称、宏名称或宏参数。同一个标识符在程序的不同位置可以表示不同的实体。枚举的成员称为枚举常量。
宏名称和宏参数在此不再考虑,因为在程序翻译的语义阶段之前,源文件中任何宏名称的出现都将被替换为构成它们的宏定义的预处理记号序列。
此外,请注意 POSIX 也保留了
_t
后缀 - 参见
编译环境。
话虽如此,思考过程似乎是“这个名称不应该经常使用;用下划线作为前缀来防止使用”。还有“我看到它在系统头文件中使用了;我会复制那种风格”,没有意识到系统头文件是这样编码的,以避免踩在普通程序员保留的命名空间上,并使用保留给实现的命名空间。
你的改写很明智;这是我通常做的事情。
针对扩展问题:
并非所有人都知道结构标签与普通标识符不在同一命名空间中,因此他们不知道typedef struct Book Book;
是完全安全和明确的(第一个Book
在标签名称空间中,必须在前面加上struct
;第二个Book
在普通标识符名称空间中,必须不在前面加上struct
)。
此外,人们看到系统头文件并查看它们的用法,认为他们应该复制那里的样式,而不知道实现对其可使用的名称有不同的规则。
请注意,Linux内核编码标准不鼓励使用结构类型的typedefs;它们要求你在任何地方都使用struct WhatEver
。这条规则有一些优点和一些缺点——自我一致性可能比使用哪种约定更重要。这意味着对于现有项目,“随波逐流”,但对于自己的新项目,无论你选择哪种方式,只要保持一致即可。
你还可以在经典著作《C程序设计语言》中找到使用结构标签和相应的typedef名称的替代名称的先例。(有趣的是,在1978年第一版和1988年第二版之间,他们的示例发生了很大变化。)
第二版:
typedef struct tnode *Treeptr;
typedef struct tnode {
…
Treeptr left;
Treeptr right;
} Treenode;
第一版:
typedef struct tnode {
…
struct tnode *left;
struct tnode *right;
} TREENODE, *TREEPTR;
请注意,现代风格倾向于避免使用typedef指针。请参见
typedef指针是个好主意吗?。