首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用匿名结构与使用带有typedef的命名结构

使用匿名结构与使用带有typedef的命名结构
EN

Stack Overflow用户
提问于 2019-02-19 01:54:12
回答 6查看 4.4K关注 0票数 25

什么时候应该使用以下语句中的一种而不是另一种?

代码语言:javascript
复制
typedef struct Foo {
    int a;
} Bar;

代码语言:javascript
复制
typedef struct {
    int a;
} Bar;

并像这样使用它

代码语言:javascript
复制
Bar bar1 = { 5 };

我知道第二个是匿名结构,但不确定什么时候应该使用一个而不是另一个。

EN

回答 6

Stack Overflow用户

发布于 2019-02-19 02:02:23

它们几乎是等同的。实际上,您可以并且应该在这两个位置使用相同的名称。使用相同的名称,除非你能想出一个很好的理由不这样做。

需要非匿名的一种情况是,当您希望指针指向相同类型的对象时,例如在链表中。

代码语言:javascript
复制
typedef struct Node {
    struct Node* next;
    int data;
} Node;

一种替代方案:

代码语言:javascript
复制
typedef struct Node Node;

struct Node {
    Node * next;
    int data;
};

根据Linus Torvalds的说法,你应该避免使用typedefing structs,除非你想隐藏它。从Linux kernel coding style guide

请不要使用像vps_t这样的东西。使用vps_t作为结构和指针是错误的。当您在源代码中看到vps_t a;时,它是什么意思?相反,如果它写的是struct virtual_container *a;,你实际上就能知道a是什么。

很多人认为typedefs有助于提高可读性。事实并非如此。它们仅在以下情况下有用:

a)完全不透明的对象(其中typedef被用来隐藏对象是什么)。

..。

根据这一点,你永远不应该使用匿名结构,而且typedefs是严格针对接口的。所以它应该看起来像这样:

代码语言:javascript
复制
typedef struct Node {
    struct Node* next;
    int data;
} Node;

但是如果你真的在创建一个接口,你通常应该把它分成一个头文件和一个源文件。在这种情况下,将type放在头文件中,并且在源文件中根本不使用type:ed类型。

.c

代码语言:javascript
复制
struct Node {
    struct Node* next;
    int data;
} Node;

void insert(struct Node* head, int data) 
{
// Code
}    

.h

代码语言:javascript
复制
typedef struct Node Node;

void insert(Node* head, int data);

考虑到以上所有情况,使用匿名结构的唯一有效情况是同时声明一个对象,如下所示:

代码语言:javascript
复制
struct {
    int data;
    float more_data;
} myObject; 
票数 20
EN

Stack Overflow用户

发布于 2019-02-19 02:01:05

这真的无关紧要。如果你使用带标签的表单,你可以有指向struct Foo内部struct Foo的指针(又称工具栏)

代码语言:javascript
复制
typedef struct Foo{
  int a;
  struct Foo *foop;
} Bar;

但是对于第二种形式是无法做到这一点的

代码语言:javascript
复制
typedef struct {
  int a;
  //Baz *p; not valid here since Baz isn't a typename yet
} Baz;

有些代码库根本不喜欢使用结构体,每次都会简单地用typedef关键字拼写struct Foo

此外,对于第一种形式,您可以通过标记(struct Foo)或使用typedefs (Bar或任何将来/以前的typedef)来引用类型(您可以在提供定义之前执行typedef struct Foo PreviousTypedef; )。

另一方面,对于第二种形式,您只能使用Baz typedef和未来可能的typedef(您不能对结构执行前向操作,因为它没有标记)。

(请注意,typedef并不是真正用C定义类型,而是由struct optional_tag { /*...*/ }部分定义。相反,typedef提供了类型别名(因此可能应该将其命名为typealias)。

票数 7
EN

Stack Overflow用户

发布于 2019-02-19 02:01:15

有一次,如果你正在制作一个链表,就需要使用前者:

代码语言:javascript
复制
typedef struct list {
    int data;
    struct list *next;
} list;

类型定义list在结构定义中不可见,因此您需要使用实际的结构名称来创建指向它的指针。

如果你没有这样的结构,你可以使用任何一种。

但是,您不应该使用以下划线开头的标记名,例如:

代码语言:javascript
复制
typedef struct _list {
    int data;
    struct list *next;
} list;

因为以下划线开头的名称由实现保留。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54752861

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档