为什么在 typedefing 结构时使用不同的标识符? [英] Why use different identifiers when typedefing structs?

查看:28
本文介绍了为什么在 typedefing 结构时使用不同的标识符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑这个代码:

typedef struct _Node Node;

struct _Node {
    struct _Node * node;
};

或者这个:

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;
};

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;

这个例子来自 tutorialspoint 我知道他们通常不应该被认为是可靠的来源.但是这样做有什么好的理由吗?

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?

推荐答案

人们使用诸如 struct _Node 之类的名称来故意忽略标准中设置的规则(或者,更常见的是,因为他们不知道标准中规定的规则).粗略地说,标准说以下划线开头的名称大多保留用于实现",即编译器和系统库.有关详细信息,请参阅 C11 §7.1.3 保留标识符:

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:

  • 以下划线开头的所有标识符以及大写字母或另一个下划线始终保留供任何使用.
  • 以下划线开头的所有标识符始终保留用作普通名称空间和标记名称空间中具有文件范围的标识符.

另请注意§6.2.1 标识符的范围 — 强调:

一个标识符可以表示一个对象;一个函数;结构、联合或枚举的标记或成员;一个 typedef 名称;标签名称;宏名称;或宏参数.相同的标识符可以表示程序中不同点的不同实体.枚举的成员称为枚举常量.这里不再进一步考虑宏名称和宏参数,因为在程序翻译的语义阶段之前,源文件中出现的任何宏名称都被构成宏定义的预处理标记序列替换.

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.

还要注意,POSIX 也保留了 _t 后缀 — 参见 编译环境.

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.

解决扩展问题:

不是每个人都知道结构标记与普通标识符位于不同的命名空间中,因此他们不知道 typedef struct Book Book; 是完全安全和明确的(第一个 Book 在标记命名空间中,必须以 struct 开头;第二个 Book 在普通标识符命名空间中,必须不是 前面是 struct).

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.

请注意 Linux 内核编码标准 不鼓励将 typedef 用于结构类型;它们要求您在任何地方使用 struct WhatEver.该规则有一些优点和一些缺点——自我一致性可能比您使用的约定更重要.这意味着对现有项目顺其自然",但只要您保持一致,在您自己的新项目中采用哪种方式并不重要.

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.

您还可以在圣经中找到使用结构标记的替代名称和相应的 typedef 名称的先例——意思是 Kernighan 和 Ritchie 的C 编程语言".(有趣的是,他们的例子在 1978 年第一版和 1988 年第二版之间发生了很大变化.)

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

第二版:

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 是个好主意吗?.

Note that modern style tends to avoid using typedef for pointers. See Is it a good idea to typedef pointers?.

这篇关于为什么在 typedefing 结构时使用不同的标识符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆