简体   繁体   English

使用匿名结构与使用typedef的命名结构

[英]Using an anonymous struct vs a named struct with typedef

When should one of the following statements be used over the other? 何时应该使用以下陈述之一?

typedef struct Foo {
    int a;
} Bar;

and

typedef struct {
    int a;
} Bar;

and use it like 并使用它

Bar bar1 = { 5 };

I understand the second on is an anonymous struct but not sure when should one be used over the other. 我理解第二个是匿名结构但不确定何时应该使用另一个结构。

They are pretty much equivalent. 它们非常相同。 Actually, you can and should use the same name on both places. 实际上,您可以而且应该在两个地方使用相同的名称。 Use the same name unless you can come up with a good reason not to. 使用相同的名称,除非你有充分的理由不这样做。

One situation where you want the non-anonymous is when you want pointers to an object of the same type, like in a linked list. 您希望非匿名的一种情况是,您希望指向相同类型的对象,例如链接列表。

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

One alternative: 一种选择:

typedef struct Node Node;

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

According to Linus Torvalds, you should avoid typedefing structs unless you want to hide it. 根据Linus Torvalds的说法,你应该避免使用typedefing结构,除非你想隐藏它。 From the Linux kernel coding style guide : Linux内核编码风格指南

Please don't use things like vps_t. 请不要使用像vps_t这样的东西。 It's a mistake to use typedef for structures and pointers. 将typedef用于结构和指针是错误的。 When you see a vps_t a; 当你看到一个vps_t a; in the source, what does it mean? 在源头,这是什么意思? In contrast, if it says struct virtual_container *a; 相反,如果它说struct virtual_container *a; you can actually tell what a is. 你真的可以告诉它是什么。

Lots of people think that typedefs help readability. 很多人认为typedef有助于提高可读性。 Not so. 不是这样。 They are useful only for: 它们仅适用于:

a) totally opaque objects (where the typedef is actively used to hide what the object is). a)完全不透明的对象(其中typedef主动用于隐藏对象的内容)。

... ...

According to that, you should never use anonymous structs, and the typedefs are strictly for interfaces. 根据这一点,你永远不应该使用匿名结构,typedef严格用于接口。 So it should look like this: 所以看起来应该是这样的:

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

But if you are really creating an interface, you should in general separate it into a header file and a source file. 但是如果你真的在创建一个接口,你通常应该将它分成头文件和源文件。 In this case, put the typedef in the header file and do NOT use the typedef:ed type at all in the source file. 在这种情况下,将typedef放在头文件中,不要在源文件中使用typedef:ed类型。

.c 。C

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

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

.h 。H

typedef struct Node Node;

void insert(Node* head, int data);

Taking all of the above into consideration, the only valid situation to use an anonymous struct is if you declare an object at the same time like this: 考虑到以上所有因素,使用匿名结构的唯一有效情况是,如果您同时声明一个对象,如下所示:

struct {
    int data;
    float more_data;
} myObject; 

One time where the former is required is if you're making a linked list: 有一次需要前者是你要制作一个链表:

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

The typedef list is not visible inside of the struct definition, so you need to use the actual struct name to create a pointer to it. typedef list在struct定义list是不可见的,因此您需要使用实际的struct name来创建指向它的指针。

If you don't have such a structure, you can use either one. 如果您没有这样的结构,可以使用其中任何一种。

What you shouldn't do however is use a tag name that starts with an underscore, ie: 但是,您不应该使用以下划线开头的标记名称,即:

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

Because names starting with a underscore are reserved by the implementation. 因为实现保留了以下划线开头的名称。

It doesn't really matter much. 这并不重要。 If you use the tagged form you can have pointers to struct Foo inside struct Foo (AKA Bar) 如果你使用标记的表单,你可以在struct Foo (AKA Bar)中有指向struct Foo指针

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

but there's no way to do that with the second form 但是第二种形式没有办法做到这一点

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

Some codebases prefer not to use typedef s at all and simply spell out struct Foo with the struct keyword every time. 有些代码库根本不喜欢使用typedef ,而只是每次都用struct关键字拼出struct Foo

Also, with the first form, you can refer to the type either via the tag ( struct Foo ) or with typedefs ( Bar or any future/previous typedef s (you can do typedef struct Foo PreviousTypedef; before you provide the definition). 此外,使用第一种形式,您可以通过标签( struct Foo )或使用typedefsBar或任何future / previous typedef s(您可以在提供定义之前执行typedef struct Foo PreviousTypedef; )来引用类型)。

With the second form, on the other hand, you can only use the Baz typedef and possible future typedef s (you can't forward- typedef the struct since it doesn't have a tag). 随着第二种形式,在另一方面,你只能使用Baz typedef和未来可能typedef S(你不能正向typedef的结构,因为它没有一个标签)。

(Note that typedef doesn't really define types in C. The struct optional_tag { /*...*/ } part does. Rather, typedef provides type aliases (so perhaps it should have been named typealias ).) (注意, typedef并没有真正定义C中的类型。 struct optional_tag { /*...*/ }部分确实如此。而是, typedef提供了类型别名(所以也许它应该被命名为typealias )。)

The term anonymous struct is already used for something else: in nested structs (or unions) that don't have a name at all and whose fields are referred to as if they were entries in the parent. 术语匿名结构已用于其他内容:在嵌套结构(或联合)中,根本没有名称,其字段被称为父项中的条目。

The actual question about when to use one or the other is that you have to use the first form if you want to add a pointer to its own type inside it like so: 关于何时使用其中一个的实际问题是,如果要在其中添加指向其自身类型的指针,则必须使用第一个表单,如下所示:

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

However, what I would prefer is to do that with a typedef like so: 但是,我更喜欢用typedef这样做:

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

A lot of other people are focusing on the self referential aspect of this, but another reason to avoid doing this is that due to the lack of namespaces in C. In some circles it is standard practice to not typedef structs to avoid struct qualifier and instead refer to structs with the full specifier (eg void foo(struct Foo* foo_ptr) ). 很多其他人都在关注自我引用的方面,但是避免这样做的另一个原因是由于C中缺少命名空间。在某些圈子中,标准做法是不要typedef结构以避免使用struct限定符而是引用具有完整说明符的结构(例如void foo(struct Foo* foo_ptr) )。 So if you wanted to maintain such a style, you wouldn't have the option to abuse anonymous structs, so this: 所以如果你想保持这样的风格,你就没有选择滥用匿名结构,所以这个:

typedef struct {
  int a;
} Bar;

Bar bar1 = {5};

should always instead be 应该总是这样

struct Bar{
  int a;
};

struct Bar bar1 = {5};

otherwise you couldn't even compile bar1's instantiation with out typedef ing away the struct qualifier 否则,你甚至无法编译BAR1的实例与出typedef荷兰国际集团走struct预选赛

When creating an opaque data type which is when the header only contains a forward declaration of the struct and the actual definition of it's members is in the source file. 当创建一个不透明的数据类型,其是当标题只包含的前向声明struct和它的部件的实际定义是源文件英寸 Since you cannot forward declare a typedef you'll have to give a struct a name. 由于您无法转发声明typedef您必须为struct命名。 Example: 例:

Foo.h foo.h中

typedef struct Foo_ Foo;

Foo.c foo.c的

struct Foo_ {
    int a;
};

Also when you have a recursive data structure such as linked list which everyone else has mentioned. 此外,当您有一个递归数据结构,如链接列表,其他人都提到过。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM