How to properly use `typedef` for structs in C?
Asked Answered
U

2

9

I see a lot of different typedef usages in many C courses and examples.

Here is the CORRECT way to do this (example from ISO/IEC C language specification draft)

typedef struct tnode TNODE;

struct tnode {
    int count;
    TNODE *left, *right;
};

TNODE s, *sp;

However I see a lot of code with the following pattern:

typedef struct {
    int a;
    int b;
} ab_t;

Is this wrong for some reasons, or correct but it provides limited functionality of structs defined like this?

Upshaw answered 25/2, 2022 at 19:39 Comment(7)
Both mechanisms work; neither is more proper than the other — but they are not always interchangeable. There's another variant: typedef struct tnode { int count; struct tnode *left; struct tnode *right; } TNODE; which uses the tagged structure name inside the structure because the typedef name isn't available until after the semicolon at the end. For most practical purposes, this is equivalent to the first example.Giovanna
Note that structure tags are in a separate namespace from typedef names, so it is legitimate to use typedef struct tagname tagname;. The body of the structure can appear between the two occurrences of tagname. (C++ provides essentially this service automatically; after declaring struct tag, the plain name tag is available for use too.)Giovanna
I wouldn't say there's one way that's CORRECT. There are quite a few different but equally correct ways of giving struct tags and typedef names to structures. This is not a matter of objective correctness, it's a subjective matter of style.Jerald
Note that the quoted passage isn't (necessarily) meant to encourage using typedef for structs. It serves as a demonstration how an incomplete type can (not necessarily should) be used with a typedef. According to my personal taste (and it's a matter of taste) structs rarely need to be typedef'd. They are what they are, and an alias (the typedef) only reduces readability because the reader needs to look up the indirection.Transcription
I contend that typedef is way overused. It provides a convenience -- occasionally a considerable one -- but it is usually possible to write clean, clear C code without ever declaring a typedef. Indeed, I would go so far as to argue that declaring and using typedefs is usually more obfuscatory than not. When that year comes that I get around to writing my C book, typedef will go into one of the "advanced topics" chapters.Cyrilcyrill
@JohnBollinger Types like FILE are nice abstract types. From a user standpoint, it makes no difference if it is a struct, union, int, etc. Without typedef, users would lose the ability to form similar abstract types.Tierza
True, @chux. And although I do not consider that ability altogether valueless, I also do not consider it to be of particularly high value under most circumstances.Cyrilcyrill
T
12

What this does:

typedef struct {
    int a;
    int b;
} ab_t;

Is define an anonymous struct and give it the alias ab_t. For this case there's no problem as you can always use the alias. It would however be a problem if one of the members was a pointer to this type.

If for example you tried to do something like this:

typedef struct {
    int count;
    TNODE *left, *right;
} TNODE;

This wouldn't work because the type TNODE is not yet defined at the point it is used, and you can't use the tag of the struct (i.e. the name that comes after the struct keyword) because it doesn't have one.

Temekatemerity answered 25/2, 2022 at 19:44 Comment(0)
A
7

The difference between these two typedef declarations

typedef struct tnode TNODE;

struct tnode {
    int count;
    TNODE *left, *right;
};

TNODE s, *sp;

and

typedef struct {
    int a;
    int b;
} ab_t;

. is that in the second case you declared an unnamed structure. It means that within the structure you can not refer to itself. For example you can not write

typede struct {
    int count;
    TNODE *left, *right;
} TNODE;

because the name TNODE used in this member declaration

    TNODE *left, *right;

is not declared yet.

But you can refer to the structure if the structure tag will have a name like

struct tnode {
    int count;
    struct tnode *left, *right;
};

because the name struct tnode was already declared.

Another difference is that to declare a pointer to a structure there is no need to have a complete definition of the structure. That is you may write

typedef struct tnode TNODE;

TNODE *sp;

struct tnode {
    int count;
    TNODE *left, *right;
};

Pay attention to that you may write a typedef declaration also the following way

struct tnode {
    int count;
    struct tnode *left, *right;
} typedef TNODE;
Aeroembolism answered 25/2, 2022 at 20:36 Comment(1)
While I suspect that placing the typedef storage class where you did (in struct tnode { … } typedef TNODE; is 'legal', it most certainly is unorthodox, and placing the 'storage class' other than first is obsolescent (deprecated) (§6.11.5 Storage classes). In this context, typedef is a 'storage class'. You should use typedef struct tnode { … } TNODE; according to §6.11.5.Giovanna

© 2022 - 2024 — McMap. All rights reserved.