使用匿名结构vs带有typedef的命名结构

时间:2019-02-18 17:54:12

标签: c

何时应使用以下一种说法?

typedef struct Foo {
    int a;
} Bar;

typedef struct {
    int a;
} Bar;

并像使用它

Bar bar1 = { 5 };

我知道第二个是匿名结构,但不确定何时应使用另一个。

6 个答案:

答案 0 :(得分:16)

它们几乎相等。实际上,您可以在两个地方使用相同的名称。那你应该使用相同的名称,除非您有充分的理由不这样做。

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

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

一种选择:

typedef struct Node Node;

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

根据Linus Torvalds,除非要隐藏它,否则应避免使用typedefing结构。来自Linux kernel coding style guide

  

请不要使用vps_t之类的内容。对结构和指针使用typedef是错误的。当您在来源中看到vps_t a;时,是什么意思?相反,如果它说struct virtual_container *a;,您实际上可以知道a是什么。

     

许多人认为typedef有助于提高可读性。不是这样它们仅对以下有用:

     

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

     

...

答案 1 :(得分:6)

如果要创建链接列表,则一次需要使用前者:

typedef struct list {
    int data;
    struct list *next;
} list;

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

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

但是,您不应该使用以下划线开头的标签名称,即:

typedef struct _list {
    int data;
    struct list *next;
} list;

由于该实现保留了以下划线开头的名称。

答案 2 :(得分:5)

这并不重要。如果您使用加标签的表格,则可以 struct Foo(又称Bar)中有指向struct Foo的指针

typedef struct Foo{
  int a;
  struct Foo *foop;
} Bar;

但无法使用第二种形式

typedef struct {
  int a;
  //Baz *p; not valid here since Baz isn't a typename yet
} Baz;

某些代码库宁愿根本不使用typedef,而每次都只用struct关键字拼出struct Foo

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

另一方面,使用第二种形式,您只能使用Baz typedef和将来可能使用的typedef s(您不能转发-typedef struct,因为它没有标签。

(请注意,typedef并没有在C中定义类型。struct optional_tag { /*...*/ }部分确实定义了类型。相反,typedef提供了类型别名(因此它应该被命名为{{1 }})。

答案 3 :(得分:3)

术语匿名结构已用于其他用途:在根本没有名称且其字段被称为它们是字段条目的嵌套结构(或联合)中。父母。

关于何时使用一个或另一个的实际问题是,如果要在其中添加指向其自身类型的指针,则必须使用第一种形式:

typedef struct Foo { struct Foo* Child; ... } Foo;

但是,我更喜欢用这样的typedef来做到这一点:

typedef struct Foo Foo;
struct Foo {Foo* Child;};

答案 4 :(得分:3)

许多其他人都在关注此方法的自引用方面,但是避免这样做的另一个原因是由于C中缺少名称空间。在某些圈子中,不{{ 1}}结构应避免使用typedef限定符,而应使用带有完整说明符的结构(例如struct)。因此,如果您想保持这种风格,就无法选择滥用匿名结构,因此:

void foo(struct Foo* foo_ptr)

应该始终是

typedef struct {
  int a;
} Bar;

Bar bar1 = {5};

否则,即使没有struct Bar{ int a; }; struct Bar bar1 = {5}; 离开typedef限定符,您甚至无法编译bar1的实​​例化

答案 5 :(得分:2)

创建不透明的数据类型时,即标头仅包含struct的前向声明,并且其成员的实际定义在源文件中。由于您无法转发声明typedef ,因此必须给struct命名。示例:

Foo.h

typedef struct Foo_ Foo;

Foo.c

struct Foo_ {
    int a;
};

同样,当您拥有递归数据结构(例如,其他所有人都提到的链表)时。