为什么在typedefing结构时使用不同的标识符?

问题描述 投票:3回答:1

考虑以下代码:

typedef struct _Node Node;

struct _Node {
    struct _Node * node;
};

或这个:

typedef struct _Node {
    struct _Node * node;
} Node;

是否有任何理由不重写它们

typedef struct Node Node;

struct Node {
    Node * node;
};

typedef struct Node {
    Node * node;
} Node;

据我所知,它们是等价的。这些下划线前缀的原因是什么?我还看到了其他变体,它不是下划线,而是第一次出现的大写字母和第二次出现的小写字母,或其他使它们不同的东西。一个例子是:

typedef struct Books {
   char title[50];
   char author[50];
   char subject[100];
   int book_id;
} Book;

这个例子来自tutorialspoint,我知道它们通常不应被视为可靠的来源。但这样做有什么好的理由吗?

c struct typedef
1个回答
5
投票

人们使用像struct _Node这样的名称故意忽略标准中规定的规则(或者更常见的是,因为他们不知道标准中规定的规则)。粗略地说,标准表示以下划线开头的名称主要是为“实现”保留的,这意味着编译器和系统库。有关详细信息,请参阅C11 §7.1.3 Reserved identifiers

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

另请注意§6.2.1 Scopes of identifiers - 重点补充:

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

另请注意,POSIX也保留了_t后缀 - 请参阅The Compilation Environment

也就是说,思考过程似乎是“这个名称不应该使用太多;前缀为下划线以阻止其使用”。并且“我已经看到它在系统头文件中使用;我将复制该样式”,没有意识到系统头文件的编码方式是为了避免为普通程序员保留的命名空间,并使用为实现保留的命名空间。

你的改写是明智的;这就是我通常做的事情。


解决扩展的问题:

并非所有人都知道结构标签与普通标识符位于不同的名称空间中,因此他们不知道typedef struct Book Book;是完全安全且明确的(第一个Book位于标签名称空间中,必须在struct之前;第二个Book是在普通标识符名称空间中,不得以struct开头)。

此外,人们会查看系统标题,看看他们做了什么,并认为他们应该在那里复制样式,而不是意识到实现有不同的规则强加于它可以和不能用于名称。

请注意,Linux kernel coding standards不鼓励将typedef用于结构类型;他们要求你到处使用struct WhatEver。规则有一些优点和一些缺点 - 自我一致性可能比你使用的约定更重要。对于现有项目来说,这意味着“顺其自然”,但只要您保持一致,那么您在自己的新项目中执行此操作的方式并不重要。

您还可以找到在圣经中使用结构标签的替代名称和相应的typedef名称的先例 - 这意味着Kernighan和Ritchie的“C编程语言”。 (有趣的是,他们的例子在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作为指针。见Is it a good idea to typedef pointers?

© www.soinside.com 2019 - 2024. All rights reserved.