Using an anonymous struct vs a named struct with typedef

前端 未结 6 1224
小蘑菇
小蘑菇 2020-12-06 16:31

When should one of the following statements be used over the other?

typedef struct Foo {
    int a;
} Bar;

and

typedef stru         


        
相关标签:
6条回答
  • 2020-12-06 16:43

    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. Since you cannot forward declare a typedef you'll have to give a struct a name. Example:

    Foo.h

    typedef struct Foo_ Foo;
    

    Foo.c

    struct Foo_ {
        int a;
    };
    

    Also when you have a recursive data structure such as linked list which everyone else has mentioned.

    0 讨论(0)
  • 2020-12-06 16:48

    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 struct Foo Foo;
    struct Foo {Foo* Child;};
    
    0 讨论(0)
  • 2020-12-06 16:51

    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.

    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, i.e.:

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

    Because names starting with a underscore are reserved by the implementation.

    0 讨论(0)
  • 2020-12-06 16:53

    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)). 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 typedefing away the struct qualifier

    0 讨论(0)
  • 2020-12-06 16:58

    It doesn't really matter much. If you use the tagged form you can have pointers to struct Foo inside struct Foo (AKA Bar)

    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 typedefs at all and simply spell out struct Foo with the struct keyword every time.

    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 typedefs (you can do typedef struct Foo PreviousTypedef; before you provide the definition).

    With the second form, on the other hand, you can only use the Baz typedef and possible future typedefs (you can't forward-typedef the struct since it doesn't have a tag).

    (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).)

    0 讨论(0)
  • 2020-12-06 16:59

    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. From the Linux kernel coding style guide:

    Please don’t use things like vps_t. It’s a mistake to use typedef for structures and pointers. When you see a vps_t a; in the source, what does it mean? In contrast, if it says struct virtual_container *a; you can actually tell what a is.

    Lots of people think that typedefs help readability. Not so. They are useful only for:

    a) totally opaque objects (where the typedef is actively used to hide what the object is).

    ...

    According to that, you should never use anonymous structs, and the typedefs are strictly for interfaces. 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.

    .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);
    

    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; 
    
    0 讨论(0)
提交回复
热议问题