什么时候应该使用以下语句之一而不是其他语句?
typedef struct Foo { int a; } Bar;
和
typedef struct { int a; } Bar;
然后用它来
Bar bar1 = { 5 };
我知道第二个是一个匿名结构,但不确定什么时候应该使用一个。
h7appiyu1#
它们几乎是等同的。事实上,你可以而且应该在两个地方使用相同的名称。使用相同的名称,除非你能想出一个很好的理由。需要非匿名的一种情况是,当你想要指向同一类型的对象的指针时,比如在链表中。
typedef struct Node { struct Node* next; int data; } Node;
一个替代方案:
typedef struct Node Node; struct Node { Node * next; int data; };
根据Linus Torvalds的说法,你应该避免类型定义结构,除非你想隐藏它。来自Linux内核编码风格指南:请不要使用vps_t之类的东西。对结构和指针使用typedef是错误的。当你在源代码中看到vps_t a;时,它意味着什么?相反,如果它写的是struct virtual_container *a;,你实际上可以知道a是什么。很多人认为typedef有助于可读性。并非如此。它们仅用于:a)完全不透明的对象(typedef被主动用来隐藏对象是什么)。...根据这一点,你永远不应该使用匿名结构体,并且typedef是严格用于接口的。所以它应该看起来像这样:
vps_t a;
struct virtual_container *a;
但是如果你真的要创建一个接口,一般来说你应该把它分成一个头文件和一个源文件。在这种情况下,将typedef放在头文件中,并且在源文件中根本不使用typedef:ed类型。.c
struct Node { struct Node* next; int data; } Node; void insert(struct Node* head, int data) { // Code }
.h
typedef struct Node Node; void insert(Node* head, int data);
考虑到以上所有情况,使用匿名结构的唯一有效情况是,如果你像这样同时声明一个对象:
struct { int data; float more_data; } myObject;
xcitsw882#
其实也没什么关系。如果你使用带标签的表单,你可以在struct Foo(AKA Bar)中有指向struct Foo的指针。
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 s,而只是每次都用struct关键字拼写struct Foo。此外,对于第一种形式,您可以通过标记(struct Foo)或typedefs(Bar或任何将来/以前的typedef s)引用类型(您可以在提供定义之前执行typedef struct Foo PreviousTypedef;)。另一方面,对于第二种形式,您只能使用Baztypedef和可能的未来typedef s(您不能转发-typedef结构体,因为它没有标记)。(Note typedef并没有真正定义C中的类型。struct optional_tag { /*...*/ }部分可以。相反,typedef提供了类型别名(因此可能应该命名为typealias)。
typedef
typedefs
Bar
typedef struct Foo PreviousTypedef;
Baz
struct optional_tag { /*...*/ }
typealias
mtb9vblg3#
有一次需要前者的是如果你正在制作一个链表:
typedef struct list { int data; struct list *next; } list;
typedef list在结构定义中不可见,因此需要使用实际的结构名称来创建指向它的指针。如果你没有这样的结构,你可以使用任何一个。但是,你不应该使用以下划线开头的标签名称,即:
list
typedef struct _list { int data; struct list *next; } list;
因为以下划线开头的名称是由实现保留的。
pkwftd7m4#
术语 anonymous struct 已经用于其他用途:在嵌套的结构(或联合)中,它们根本没有名称,并且其字段被引用,就好像它们是父级中的条目一样。关于什么时候使用一个或另一个的实际问题是,如果你想在它里面添加一个指向自己类型的指针,你必须使用第一种形式:
typedef struct Foo { struct Foo* Child; ... } Foo;
然而,我更喜欢用这样的typedef来做这件事:
typedef struct Foo Foo; struct Foo {Foo* Child;};
13z8s7eq5#
很多其他人都在关注它的自引用方面,但避免这样做的另一个原因是,由于C中缺乏名称空间。在某些圈子里,标准的做法是不引用typedef结构以避免struct限定符,而是引用具有完整说明符的结构(例如void foo(struct Foo* foo_ptr))。所以如果你想保持这样的风格,你就不能选择滥用匿名结构,所以:
struct
void foo(struct Foo* foo_ptr)
typedef struct { int a; } Bar; Bar bar1 = {5};
应该总是
struct Bar{ int a; }; struct Bar bar1 = {5};
否则,你甚至不能编译bar1的示例化,而去掉struct限定符
vcudknz36#
当创建一个不透明的数据类型时,头文件只包含struct的前向声明,其成员的实际定义在源文件中。因为你不能向前声明一个typedef,你必须给予一个struct一个名字。范例:Foo.h
typedef struct Foo_ Foo;
Foo.c
struct Foo_ { int a; };
当你有一个递归的数据结构,如链表,其他人都提到过。
6条答案
按热度按时间h7appiyu1#
它们几乎是等同的。事实上,你可以而且应该在两个地方使用相同的名称。使用相同的名称,除非你能想出一个很好的理由。
需要非匿名的一种情况是,当你想要指向同一类型的对象的指针时,比如在链表中。
一个替代方案:
根据Linus Torvalds的说法,你应该避免类型定义结构,除非你想隐藏它。来自Linux内核编码风格指南:
请不要使用vps_t之类的东西。对结构和指针使用typedef是错误的。当你在源代码中看到
vps_t a;
时,它意味着什么?相反,如果它写的是struct virtual_container *a;
,你实际上可以知道a是什么。很多人认为typedef有助于可读性。并非如此。它们仅用于:
a)完全不透明的对象(typedef被主动用来隐藏对象是什么)。
...
根据这一点,你永远不应该使用匿名结构体,并且typedef是严格用于接口的。所以它应该看起来像这样:
但是如果你真的要创建一个接口,一般来说你应该把它分成一个头文件和一个源文件。在这种情况下,将typedef放在头文件中,并且在源文件中根本不使用typedef:ed类型。
.c
.h
考虑到以上所有情况,使用匿名结构的唯一有效情况是,如果你像这样同时声明一个对象:
xcitsw882#
其实也没什么关系。如果你使用带标签的表单,你可以在
struct Foo
(AKA Bar)中有指向struct Foo
的指针。但是第二种形式是不可能的
有些代码库根本不喜欢使用
typedef
s,而只是每次都用struct关键字拼写struct Foo
。此外,对于第一种形式,您可以通过标记(
struct Foo
)或typedefs
(Bar
或任何将来/以前的typedef
s)引用类型(您可以在提供定义之前执行typedef struct Foo PreviousTypedef;
)。另一方面,对于第二种形式,您只能使用
Baz
typedef
和可能的未来typedef
s(您不能转发-typedef
结构体,因为它没有标记)。(Note
typedef
并没有真正定义C中的类型。struct optional_tag { /*...*/ }
部分可以。相反,typedef
提供了类型别名(因此可能应该命名为typealias
)。mtb9vblg3#
有一次需要前者的是如果你正在制作一个链表:
typedef
list
在结构定义中不可见,因此需要使用实际的结构名称来创建指向它的指针。如果你没有这样的结构,你可以使用任何一个。
但是,你不应该使用以下划线开头的标签名称,即:
因为以下划线开头的名称是由实现保留的。
pkwftd7m4#
术语 anonymous struct 已经用于其他用途:在嵌套的结构(或联合)中,它们根本没有名称,并且其字段被引用,就好像它们是父级中的条目一样。
关于什么时候使用一个或另一个的实际问题是,如果你想在它里面添加一个指向自己类型的指针,你必须使用第一种形式:
然而,我更喜欢用这样的typedef来做这件事:
13z8s7eq5#
很多其他人都在关注它的自引用方面,但避免这样做的另一个原因是,由于C中缺乏名称空间。在某些圈子里,标准的做法是不引用
typedef
结构以避免struct
限定符,而是引用具有完整说明符的结构(例如void foo(struct Foo* foo_ptr)
)。所以如果你想保持这样的风格,你就不能选择滥用匿名结构,所以:应该总是
否则,你甚至不能编译bar1的示例化,而去掉
struct
限定符vcudknz36#
当创建一个不透明的数据类型时,头文件只包含
struct
的前向声明,其成员的实际定义在源文件中。因为你不能向前声明一个typedef
,你必须给予一个struct
一个名字。范例:Foo.h
Foo.c
当你有一个递归的数据结构,如链表,其他人都提到过。