何时应使用以下一种说法?
typedef struct Foo {
int a;
} Bar;
和
typedef struct {
int a;
} Bar;
并像使用它
Bar bar1 = { 5 };
我知道第二个是匿名结构,但不确定何时应使用另一个。
答案 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
)或typedefs
(Bar
或任何将来/以前的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;
};
同样,当您拥有递归数据结构(例如,其他所有人都提到的链表)时。