447

I have seen many programs consisting of structures like the one below

typedef struct 
{
    int i;
    char k;
} elem;

elem user;

Why is it needed so often? Any specific reason or applicable area?

nbro
  • 12,226
  • 19
  • 85
  • 163
Manoj Doubts
  • 11,957
  • 15
  • 39
  • 42
  • 15
    More thorough and precise answer: http://stackoverflow.com/questions/612328/difference-between-struct-and-typedef-struct-in-c – AbiusX Mar 17 '11 at 02:14
  • It has disadvantages I think you can't create a link list with anonymous struct because the line `struct * ptr` inside the struct will cause error – Raghib Ahsan Feb 01 '16 at 17:40
  • 11
    The 'more thorough and precise answer' is [Difference between struct and typedef struct in C++](https://stackoverflow.com/questions/612328/), and there are significant differences between C and C++ in this area which make that answer not wholly appropriate for a question about C. – Jonathan Leffler Jun 05 '16 at 22:21
  • This question has a duplicate [typedef struct vs struct definitions](https://stackoverflow.com/questions/1675351/typedef-struct-vs-struct-definitions/) that also has stellar answers. – Jonathan Leffler Jun 05 '16 at 22:25
  • 2
    OTOH, https://www.kernel.org/doc/html/v4.10/process/coding-style.html tells us that we shouldn't do such typedefs. – glglgl Mar 27 '18 at 15:52

15 Answers15

490

As Greg Hewgill said, the typedef means you no longer have to write struct all over the place. That not only saves keystrokes, it also can make the code cleaner since it provides a smidgen more abstraction.

Stuff like

typedef struct {
  int x, y;
} Point;

Point point_new(int x, int y)
{
  Point a;
  a.x = x;
  a.y = y;
  return a;
}

becomes cleaner when you don't need to see the "struct" keyword all over the place, it looks more as if there really is a type called "Point" in your language. Which, after the typedef, is the case I guess.

Also note that while your example (and mine) omitted naming the struct itself, actually naming it is also useful for when you want to provide an opaque type. Then you'd have code like this in the header, for instance:

typedef struct Point Point;

Point * point_new(int x, int y);

and then provide the struct definition in the implementation file:

struct Point
{
  int x, y;
};

Point * point_new(int x, int y)
{
  Point *p;
  if((p = malloc(sizeof *p)) != NULL)
  {
    p->x = x;
    p->y = y;
  }
  return p;
}

In this latter case, you cannot return the Point by value, since its definition is hidden from users of the header file. This is a technique used widely in GTK+, for instance.

UPDATE Note that there are also highly-regarded C projects where this use of typedef to hide struct is considered a bad idea, the Linux kernel is probably the most well-known such project. See Chapter 5 of The Linux Kernel CodingStyle document for Linus' angry words. :) My point is that the "should" in the question is perhaps not set in stone, after all.

ratchet freak
  • 44,814
  • 5
  • 55
  • 99
unwind
  • 364,555
  • 61
  • 449
  • 578
  • 61
    You shouldn't use identifiers with an underscore followed by an uppercase letter, they are reserved (see section 7.1.3 paragraph 1). Although unlikely to be much of a problem, it is technically undefined behaviour when you use them (7.1.3 paragraph 2). – dreamlax Jan 06 '11 at 10:40
  • How about the pros/cons of this syntax: typedef struct Point { int x, y; } Point This link: http://en.wikipedia.org/wiki/Struct_(C_programming_language)#typedef discusses the issue but is ambiguous as to whether it's in or out of favor – dlchambers Oct 04 '11 at 12:10
  • Answer to my own question: http://stackoverflow.com/questions/1110944/c-typedef-and-struct-question – dlchambers Oct 04 '11 at 12:14
  • 17
    @dreamlax: In case it wasn't clear to others, that's only _starting_ an identifier with an underscore and an upper case that you shouldn't do; you're free to use that in the middle of an identifier. – brianmearns Jan 16 '12 at 17:08
  • 13
    It's interesting that the example given here (in which the typedef prevents using "struct" "all over the place") is actually longer than the same code without the typedef, since it saves exactly one use of the word "struct". The smidgen of abstraction gained rarely compares favorable with the additional obfuscation. – William Pursell Jan 25 '12 at 14:15
  • 1
    @WilliamPursell How do you count to get one? I see three; one in the header and two in the implementation file. Maybe I'm just confused. – unwind Dec 18 '12 at 15:54
  • 1
    @unwind Many months have passed, so I cannot be sure of what I was thinking, and I agree with your count. Perhaps I was thinking of the following very poor style: header file with just `struct point * point_new(int x, int y);` (combining the forward declaration of the struct with the function declaration) and implementation file `struct point { int x,y; } * point_new( ...` (combining the struct definition with the function declaration). – William Pursell Dec 23 '12 at 17:01
  • @dreamlax I recall that many Gstreamer code defines structures with an alias following the pattern _[A-Z].* ... And it works very well. Could you explain a little more (a link in comment would satisfy me). Btw, sorry for the "necromancing" – Rerito Jan 30 '13 at 21:42
  • 1
    @Rerito: It's usually no big deal. Identifiers such as `_[A-Z_].*` are reserved for future use. For example, C99 introduced `_Bool` and C11 introduced `_Atomic` and `_Thread_local` (among many others). All of these were named this way because they were out of the "reserved" pool, and anyone who already used these keywords/identifiers in their own code violated a rule. It *usually* poses no risk to use `_StructName` etc. *Technically* according to the standard, it is undefined behaviour to use a name like that, but I've yet to encounter a situation where it mattered. – dreamlax Jan 30 '13 at 22:10
  • 7
    @Rerito fyi, page 166 of [C99 draft](http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf), *All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.* And *All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.* – Breaking not so bad Apr 15 '13 at 04:41
  • 10
    Interestingly enough, the linux kernel coding guidelines say we should be a lot more conservative about using typedefs (section 5): https://www.kernel.org/doc/Documentation/CodingStyle – gsingh2011 May 29 '13 at 00:13
  • 1
    @dreamlax "You shouldn't use identifiers with an underscore followed by an uppercase letter". Is it about names *with* underscore followed by an uppercase or *beginning with* underscore followed by an uppercase? ring0 suggests that it's the latter, but after reading your comment I thought that it's the first. – cubuspl42 Jul 05 '14 at 16:28
  • 4
    Anyone who uses typedefs like this is stupid, I hate people like this, you can't even remove the typedef.... It provides no abstraction and is the most useless thing. Please never do this, and if you have to, put the god dang typedefs in a separate header and don't force me to use it. Because I don't want them. – alternative Mar 19 '15 at 21:37
  • 5
    @alternative: In some implementations, a type like `FILE` would be better as a struct; in others, it would be better as a union. If in a particular implementation it would be better as a union, having client code say `struct FILE *` everywhere would force the implementation to wrap the union in a useless single-member structure. – supercat Mar 27 '15 at 18:53
  • 3
    @alternative: Why only the "standard" library? I would think many sorts of libraries could plausibly be best served in some implementation by having a `union` as an outer member, and in others by having a `struct`. Personally I think it would have been better if rather than having union types, C had provided more detailed control over structure layout (e.g. `struct quad { unsigned long l; unsigned char b[4] @ l;}`) in which case then the issue would be moot [actually, C would still benefit from that], but that's obviously not what happened. – supercat Apr 03 '15 at 15:58
  • 1
    @supercat but whether a non-opaque object is a struct or union is important, you should be able to immediately tell. If its opaque its not as much of an issue, and everything in standard library is opaque – alternative Apr 09 '15 at 20:03
  • @alternative: If a type has more than one non-opaque field, then whether it's a struct or union is obviously important. I don't see any reason that the C standard should be unique in having opaque or nearly-opaque types which do not expose more than one field. – supercat Apr 09 '15 at 20:21
  • Your first example the first function declares a local variable and it returns that variable (Point a). This will generate a warning and is an error. http://stackoverflow.com/questions/4824342/returning-a-local-variable-from-function-in-c – Milhous Oct 13 '15 at 01:07
  • 3
    @Milhous Not at all, I'm returning a value and not a pointer. – unwind Oct 14 '15 at 09:21
  • @unwind Ah, you are correct. but using values is a very bad practice in general. Inside the method it will copy *all* the data. You example this is ok as there are 8 bytes. But imagine if it were several megabytes. – Milhous Oct 21 '15 at 01:53
  • 7
    @Milhous That's just borkened reasoning in my opinion. A `Point` is not several megabytes. Returning values is awesome for semantics and readability, and being super-ultra-hyper-defensive and thinking "oh noes, some programs manipulate data that is too large to be returned, let's **never** return values" makes no sense to me. Use the right tool etc. – unwind Oct 22 '15 at 08:55
  • 1
    @unwind +1 Value returning functions also have the benefit that they can be marked __attribute__((const)) or pure, both of which don't work well with functions that return via a pointer parameter. It's unfortunate though, that plain C compilers don't do RVO well (=at all) on this. I played with this once and g++ had a couple of percentage points faster returns by value because of the RVO-avoided copying. – PSkocik Oct 31 '16 at 19:51
  • In the first code snippet, is'nt it misleading to return a struct allocated on stack? – AlphaGoku Jul 17 '18 at 11:26
  • I don't understand your *In this latter case, you cannot return the Point by value, since its declaration is hidden from users of the header file.* part, why it's related to `typedef`? – Kindred Nov 23 '18 at 12:44
  • Though not related to the question, can you tell me how `if((p = malloc(sizeof *p)) != NULL)` works here? Thanks in advance. – LordOfThunder Jun 23 '19 at 09:23
  • @AkshayImmanuelD No, since the struct is treated as a value, it's no different from returning an integer (compare `const int x = 17; return x;`). The entire value is copied, by value, no pointers are involved so where the original was stored doesn't matter. – unwind Jun 24 '19 at 08:34
  • 1
    @taritgoswami What part is confusing? The expression `sizeof *p` is a compile-time way to compute the number of bytes required to store whatever `p` is pointing at, and removes the need to manually enter the type name an extra time. – unwind Jun 24 '19 at 08:34
  • Thanks, and when the `(p = malloc(sizeof *p))` expression can be `NULL` ? – LordOfThunder Jun 24 '19 at 19:28
  • 1
    @taritgoswami The `malloc()` function returns `NULL` if it fails to allocate the requested amount of memory. This is basic C knowledge. – unwind Jun 26 '19 at 08:01
  • Re William Pursell comment all over the place means any time struct is used – Paul Nov 30 '19 at 04:41
  • Opposing viewpoint: using `typedef struct Xyz XYZ` and then defining a variable as having type `XYZ` instead of `struct Xyz` raises the confusion factor because `XYZ` looks like an elementary type when it *is* actually a `struct`. – Bob Jarvis - Reinstate Monica Jun 06 '20 at 15:56
  • 1
    @BobJarvis-ReinstateMonica: Another reason for favoring the `struct` keyword: one can create and use pointers to incomplete structure types identified with `struct` keyword and a tag, without a definition of the type having to be appear anywhere in the compilation unit. If one might ever need to use `struct` and a tag name, I think it's better to consistently specify the type that way than to sometimes specify it that way and sometimes use a typedef. – supercat Jun 25 '20 at 21:21
228

It's amazing how many people get this wrong. PLEASE don't typedef structs in C, it needlessly pollutes the global namespace which is typically very polluted already in large C programs.

Also, typedef'd structs without a tag name are a major cause of needless imposition of ordering relationships among header files.

Consider:

#ifndef FOO_H
#define FOO_H 1

#define FOO_DEF (0xDEADBABE)

struct bar; /* forward declaration, defined in bar.h*/

struct foo {
  struct bar *bar;
};

#endif

With such a definition, not using typedefs, it is possible for a compiland unit to include foo.h to get at the FOO_DEF definition. If it doesn't attempt to dereference the 'bar' member of the foo struct then there will be no need to include the "bar.h" file.

Also, since the namespaces are different between the tag names and the member names, it is possible to write very readable code such as:

struct foo *foo;

printf("foo->bar = %p", foo->bar);

Since the namespaces are separate, there is no conflict in naming variables coincident with their struct tag name.

If I have to maintain your code, I will remove your typedef'd structs.

Jens
  • 61,963
  • 14
  • 104
  • 160
Jerry Hicks
  • 2,584
  • 1
  • 12
  • 5
  • 42
    What's more amazing is that 13 months after this answer is given, I'm the first to upvote it! typedef'ing structs is one of the greatest abuses of C, and has no place in well-written code. typedef is useful for de-obfuscating convoluted function pointer types and really serves no other useful purpose. – William Pursell Jan 25 '12 at 14:04
  • 31
    Peter van der Linden also makes a case against typedefing structs in his enlightening book "Expert C Programming - Deep C Secrets". The gist is: You WANT to know that something is a struct or union, not HIDE it. – Jens Mar 14 '12 at 10:31
  • 34
    The Linux kernel coding style explicitly forbids typedefing structs. Chapter 5: Typedefs: "It's a _mistake_ to use typedef for structures and pointers." http://www.kernel.org/doc/Documentation/CodingStyle – jasso Dec 09 '12 at 22:39
  • 69
    What benefits, exactly, does typing "struct" over and over again provide? And speaking of pollution, why would you want to have a struct and a function/variable/typedef with the same name in a global namespace (unless it's a typedef for that same function)? The safe pattern is to use `typedef struct X { ... } X`. That way you can use the short form `X` to address the struct anywhere the definition is available, but can still forward-declare and use `struct X` when desired. – Pavel Minaev Mar 20 '13 at 07:18
  • 7
    I personal very rarely if ever use typedef, I wouldn't say other people shouldn't use it, it just not my style. I like to see a struct before a variable type so I know straight away its a struct. The easier to type argument is a bit lame, having variable that are a single letter is also easier to type, also with auto completions how hard is it to type struct nowadays anywhere. – Nathan Day Jun 01 '13 at 10:26
  • What is supposed to be the problem with `foo.h` in this example? You can still access `FOO_DEF` if you changed to `typedef struct { struct bar *bar; } foo;` – M.M Nov 06 '14 at 01:53
  • @MattMcNabb I also do not understand this, did you figure it out? – Janus Troelsen Feb 14 '15 at 21:53
  • 1
    @JanusTroelsen Yes, I see now: it's supposed to be contrasted with `struct foo { Bar *bar; };` which would require `foo.h` to include `bar.h`. – M.M Feb 14 '15 at 21:54
  • 2
    this line: ';typedef struct Point Point;' clearly makes my 'Point' about not typedef'ing a struct. The first 'Point' is a struct tag name. The second 'Point' is a 'new' type. Now, you, the compiler, and anyone else that reads the code needs to keep track of which 'Point' is meant. – user3629249 May 28 '15 at 20:43
  • 7
    @user3629249 it shouldn't be too difficult. The former will always be preceded by the `struct` keyword. – Yawar Dec 04 '16 at 05:43
  • 2
    "What benefits, exactly, does typing "struct" over and over again provide?" --- Keeps the fingers healthy through lots of exercise. – Daniel Feb 22 '17 at 18:34
  • 5
    Sorry, added a -1 :( as typedef-ing doesn't prevent any good thing you have mentioned, eg in header opaque.h: `typedef struct Opaque Opaque; extern Opaque *OpConstructor (void); extern void OpDestructor (Opaque *);` then in opaque.c: `struct Opaque { actual definition };` – Lorinczy Zsigmond May 04 '17 at 10:43
  • 2
    Ah yes, the very readable `struct foo *foo;`. Sometimes I wonder about C coders. – CivFan Sep 01 '20 at 21:50
  • @LorinczyZsigmond: If two headers both include `typedef struct Opaque Opaque;`, code that includes both would be incompatible with older compilers that have proven themselves reliable unless the headers coordinate the use of a `#define` macro (which would contribute to even worse namespace pollution) to avoid the duplicate definition. – supercat Dec 25 '20 at 17:29
  • @CivFan: If a function uses one object each of more than one structure type, and their usage doesn't fit any clear pattern like "source" and "destination", what names would you favor instead? Sure, one could use something like `struct foo *theFoo;`, but does that really make anything clearer than it otherwise would be? An identifier which emerges from the preprocessor preceded by the reserved word `struct` can't be anything other than a struct tag, so I don't see any basis for confusion. – supercat Dec 25 '20 at 17:35
  • 1
    @supercat very true, this typedef belongs into `opaque.h` which is supposed to use _include guards._ Other headers should either include `opaque.h` or use `struct Opaque` format. – Lorinczy Zsigmond Dec 27 '20 at 09:47
  • @LorinczyZsigmond: If some consumers of `woozle.h` will use a function that accepts a `struct Opaque*`, and some won't, the ones that don't use that function *shouldn't need to have opaque.h anywhere in their project*. Further, if `opaque.h` includes a function that takes a `struct woozle*`, trying to have the typedefs in each header processed before the prototypes in the other would require coordination of guard macro names between the authors of the two libraries, while simply using types `struct opaque*` and `struct woozle*` in prototypes would avoid any need to have prior definitions. – supercat Dec 27 '20 at 18:31
  • @supercat I would suggest, `struct Foo *foo`, but yes, your example would also be fine and would be very much clearer than `struct foo *foo`. – CivFan Jan 04 '21 at 23:01
  • typedef, like define is a bad practice unless absolutely necessary. I have seen the abuse of these sort of things, make code tracing impossible ( typedef in typedef in typedef in ..., define in define in define in ...) – Charlie Jan 13 '21 at 03:53
146

From an old article by Dan Saks (http://www.ddj.com/cpp/184403396?pgno=3):


The C language rules for naming structs are a little eccentric, but they're pretty harmless. However, when extended to classes in C++, those same rules open little cracks for bugs to crawl through.

In C, the name s appearing in

struct s
    {
    ...
    };

is a tag. A tag name is not a type name. Given the definition above, declarations such as

s x;    /* error in C */
s *p;   /* error in C */

are errors in C. You must write them as

struct s x;     /* OK */
struct s *p;    /* OK */

The names of unions and enumerations are also tags rather than types.

In C, tags are distinct from all other names (for functions, types, variables, and enumeration constants). C compilers maintain tags in a symbol table that's conceptually if not physically separate from the table that holds all other names. Thus, it is possible for a C program to have both a tag and an another name with the same spelling in the same scope. For example,

struct s s;

is a valid declaration which declares variable s of type struct s. It may not be good practice, but C compilers must accept it. I have never seen a rationale for why C was designed this way. I have always thought it was a mistake, but there it is.

Many programmers (including yours truly) prefer to think of struct names as type names, so they define an alias for the tag using a typedef. For example, defining

struct s
    {
    ...
    };
typedef struct s S;

lets you use S in place of struct s, as in

S x;
S *p;

A program cannot use S as the name of both a type and a variable (or function or enumeration constant):

S S;    // error

This is good.

The tag name in a struct, union, or enum definition is optional. Many programmers fold the struct definition into the typedef and dispense with the tag altogether, as in:

typedef struct
    {
    ...
    } S;

The linked article also has a discussion about how the C++ behavior of not requireing a typedef can cause subtle name hiding problems. To prevent these problems, it's a good idea to typedef your classes and structs in C++, too, even though at first glance it appears to be unnecessary. In C++, with the typedef the name hiding become an error that the compiler tells you about rather than a hidden source of potential problems.

Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185
Michael Burr
  • 311,791
  • 49
  • 497
  • 724
  • 4
    One example of where the tag name is the same as a non-tag name is in (POSIX or Unix) program with the [`int stat(const char *restrict path, struct stat *restrict buf)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html) function. There you have a function `stat` in the ordinary name space and `struct stat` in the tag name space. – Jonathan Leffler Jun 05 '16 at 22:02
  • 3
    your statement , S S; // error .... IS WRONG It works well. I mean your statement that "we cant have same name for typedef tag and var" is WRONG... pls check – eRaisedToX Aug 03 '16 at 07:24
67

Using a typedef avoids having to write struct every time you declare a variable of that type:

struct elem
{
 int i;
 char k;
};
elem user; // compile error!
struct elem user; // this is correct
Greg Hewgill
  • 828,234
  • 170
  • 1,097
  • 1,237
  • 2
    ok we are not having that problem in C++. So why dont anybody remove that glitch from the C's compiler and make it the same as in C++.ok C++ is having some different application areas and so it is having the advanced features.but can we not inherit some of them in C without changing the original C? – Manoj Doubts Oct 31 '08 at 12:03
  • 4
    Manoj, the tag name ("struct foo") is necessary when you need to define a struct that references itself. e.g. the "next" pointer in a linked list. More to the point, the compiler implements the standard, and that's what the standard says to do. – Michael Carman Oct 31 '08 at 13:05
  • 44
    It's not a glitch in the C compiler, it's part of the design. They changed that for C++, which I think makes things easier, but that doesn't mean C's behavior is wrong. – Herms Oct 31 '08 at 19:36
  • 5
    unfortunately many 'programmers' define a struct then typedef it with some 'unrelated' name (like struct myStruct ...; typedef struct myStruct susan*; In almost all instances a typedef leads to nothing but cluttering the code, hiding the actual definition of a variable/parameter, and mis-leads everyone, including the original writer of the code. – user3629249 May 28 '15 at 20:50
  • 1
    @user3629249 I agree with you that the mentioned programming style is horrible but this is not a reason to denigrate `typedef`ing structures in general. You could also do `typedef struct foo foo;`. Of course the `struct` keyword isn´t required more then which can be a useful hint that the type alias we look at is an alias for a structure but it is not bad in general. Consider also a case where the identifier of the resulting type alias of `typedef` indicates that it is an alias for a structure, f.e.: `typedef struct foo foo_struct;`. – RobertS supports Monica Cellio Feb 10 '20 at 19:38
44

One other good reason to always typedef enums and structs results from this problem:

enum EnumDef
{
  FIRST_ITEM,
  SECOND_ITEM
};

struct StructDef
{
  enum EnuumDef MyEnum;
  unsigned int MyVar;
} MyStruct;

Notice the typo in EnumDef in the struct (EnuumDef)? This compiles without error (or warning) and is (depending on the literal interpretation of the C Standard) correct. The problem is that I just created an new (empty) enumeration definition within my struct. I am not (as intended) using the previous definition EnumDef.

With a typdef similar kind of typos would have resulted in a compiler errors for using an unknown type:

typedef 
{
  FIRST_ITEM,
  SECOND_ITEM
} EnumDef;

typedef struct
{
  EnuumDef MyEnum; /* compiler error (unknown type) */
  unsigned int MyVar;
} StructDef;
StrructDef MyStruct; /* compiler error (unknown type) */

I would advocate ALWAYS typedef'ing structs and enumerations.

Not only to save some typing (no pun intended ;)), but because it is safer.

M.M
  • 130,300
  • 18
  • 171
  • 314
cschol
  • 12,025
  • 11
  • 62
  • 78
  • 3
    Even worse, your typo might coincide with a different tag. In the case of a struct this could result in the entire program compiling correctly and having runtime undefined behaviour. – M.M Feb 14 '15 at 22:15
  • 4
    this definition: 'typedef { FIRST_ITEM, SECOND_ITEM } EnumDef;' does not define an enum. I've written hundreds of huge programs and had the mis-fortune to perform maintenance on programs others have written. From the hard hand of experience, using typedef on a struct only leads to problems. Hopefully the programmer is not so handicapped that they have problems typing a full definition when they declare a struct instance. C is not Basic, so typing some more characters is not detrimental to the operation of the program. – user3629249 May 28 '15 at 20:57
  • Note, it is usually discouraged to use `enum` as a type, as many compilers emit strange warnings when using them 'wrong'. For example, initializing an `enum` to 0 might give an 'integer constant not in enum' warning. Forward-declaring an `enum` is also not allowed. One should use `int` (or `unsigned int`) instead. – yyny Nov 30 '16 at 21:31
  • 6
    That example does not compile , nor would I expect it to. Compiling Debug/test.o test.c:10:17: error: field has incomplete type 'enum EnuumDef' enum EnuumDef MyEnum; ^ test.c:10:8: note: forward declaration of 'enum EnuumDef' enum EnuumDef MyEnum; ^ 1 error generated. gnuc, with std=c99. – natersoz Jan 21 '17 at 19:49
  • 1
    In clang ang gcc with c99, that example does not compile. But seems like Visual Studio does not complain anything. http://rextester.com/WDQ5821 – mja Jun 19 '18 at 02:30
  • @M.M *"Even worse, your typo might coincide with a different tag. In the case of a struct this could result in the entire program compiling correctly and having runtime undefined behaviour."* - Could you provide an example? For what exactly would this different tag stand for? A structure tag? But don´t structure tags require the `struct` keyword preceded to define a variable of that structure? Else we would get a compiler error. How does that cause UB? – RobertS supports Monica Cellio Feb 11 '20 at 11:28
  • @cschol I would recommend you to delete this answer or change it significantly because it is simply wrong (or at least no longer correct). Neither in C nor C++ you will get the code of the first example compiled. I tested it with clang and gcc, here: https://godbolt.org/z/Moskd4, and even with older versions of those. Not only once this was getting passed without at least one error. – RobertS supports Monica Cellio Feb 11 '20 at 11:48
32

Linux kernel coding style Chapter 5 gives great pros and cons (mostly cons) of using typedef.

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

Example: "pte_t" etc. opaque objects that you can only access using the proper accessor functions.

NOTE! Opaqueness and "accessor functions" are not good in themselves. The reason we have them for things like pte_t etc. is that there really is absolutely zero portably accessible information there.

(b) Clear integer types, where the abstraction helps avoid confusion whether it is "int" or "long".

u8/u16/u32 are perfectly fine typedefs, although they fit into category (d) better than here.

NOTE! Again - there needs to be a reason for this. If something is "unsigned long", then there's no reason to do

typedef unsigned long myflags_t;

but if there is a clear reason for why it under certain circumstances might be an "unsigned int" and under other configurations might be "unsigned long", then by all means go ahead and use a typedef.

(c) when you use sparse to literally create a new type for type-checking.

(d) New types which are identical to standard C99 types, in certain exceptional circumstances.

Although it would only take a short amount of time for the eyes and brain to become accustomed to the standard types like 'uint32_t', some people object to their use anyway.

Therefore, the Linux-specific 'u8/u16/u32/u64' types and their signed equivalents which are identical to standard types are permitted -- although they are not mandatory in new code of your own.

When editing existing code which already uses one or the other set of types, you should conform to the existing choices in that code.

(e) Types safe for use in userspace.

In certain structures which are visible to userspace, we cannot require C99 types and cannot use the 'u32' form above. Thus, we use __u32 and similar types in all structures which are shared with userspace.

Maybe there are other cases too, but the rule should basically be to NEVER EVER use a typedef unless you can clearly match one of those rules.

In general, a pointer, or a struct that has elements that can reasonably be directly accessed should never be a typedef.

Community
  • 1
  • 1
Yu Hao
  • 111,229
  • 40
  • 211
  • 267
  • 6
    'Opaqueness and "accessor functions" are not good in themselves'. Can someone explain why? I would think information hiding and encapsulation would be a very good idea. – Yawar Dec 04 '16 at 05:48
  • 8
    @Yawar I just read this document and had exactly the same thought. Sure, C isn't object orientated, but abstraction is still a thing. – Baldrickk Jan 10 '17 at 16:18
  • @Yawar: I think the point was "in themselves". Suppose one has a type which is supposed to represent a 3d point using `float` coordinates. One could require that code which wants to read the `x` value of a point use an accessor function to do so, and there are times when a genuinely abstract "readable 3d point" type could be useful, but there are many other times where what's needed is a type that can do everything a `float x,y,z` triple can do, with the same semantics. In the latter situations, trying to make the type opaque would promote confusion rather than clarity. – supercat Dec 25 '20 at 17:46
16

It turns out that there are pros and cons. A useful source of information is the seminal book "Expert C Programming" (Chapter 3). Briefly, in C you have multiple namespaces: tags, types, member names and identifiers. typedef introduces an alias for a type and locates it in the tag namespace. Namely,

typedef struct Tag{
...members...
}Type;

defines two things. One Tag in the tag namespace and one Type in the type namespace. So you can do both Type myType and struct Tag myTagType. Declarations like struct Type myType or Tag myTagType are illegal. In addition, in a declaration like this:

typedef Type *Type_ptr;

we define a pointer to our Type. So if we declare:

Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;

then var1,var2 and myTagType1 are pointers to Type but myTagType2 not.

In the above-mentioned book, it mentions that typedefing structs are not very useful as it only saves the programmer from writing the word struct. However, I have an objection, like many other C programmers. Although it sometimes turns to obfuscate some names (that's why it is not advisable in large code bases like the kernel) when you want to implement polymorphism in C it helps a lot look here for details. Example:

typedef struct MyWriter_t{
    MyPipe super;
    MyQueue relative;
    uint32_t flags;
...
}MyWriter;

you can do:

void my_writer_func(MyPipe *s)
{
    MyWriter *self = (MyWriter *) s;
    uint32_t myFlags = self->flags;
...
}

So you can access an outer member (flags) by the inner struct (MyPipe) through casting. For me it is less confusing to cast the whole type than doing (struct MyWriter_ *) s; every time you want to perform such functionality. In these cases brief referencing is a big deal especially if you heavily employ the technique in your code.

Finally, the last aspect with typedefed types is the inability to extend them, in contrast to macros. If for example, you have:

#define X char[10] or
typedef char Y[10]

you can then declare

unsigned X x; but not
unsigned Y y;

We do not really care for this for structs because it does not apply to storage specifiers (volatile and const).

Yoon5oo
  • 489
  • 5
  • 11
user1533288
  • 221
  • 3
  • 6
  • 1
    `MyPipe *s; MyWriter *self = (MyWriter *) s;` and you've just broken strict aliasing. – Jonathon Reinhart Jun 01 '15 at 19:18
  • @JonathonReinhart It would be illustrative to mention how this can be avoided, for example how the hugely cast-happy GTK+ works around it: https://bugzilla.gnome.org/show_bug.cgi?id=140722 / https://mail.gnome.org/archives/gtk-devel-list/2004-April/msg00196.html – underscore_d Apr 09 '16 at 16:35
  • 1
    "typedef introduces an alias for a type and locates it in the tag namespace. Namely" `typedef struct Tag{ ...members... }Type;` "defines two things" doesn't quite make sense. if typedef defines tags then 'Type' here should also be a tag. The truth is the definition defines 2 tags and 1 type (or 2 types and 1 tag. not sure): `struct Tag`, `Tag` and `Type`. `struct Tag` is definitely a type. `Tag` is a tag. but the confusion is whether `Type` is a tag or a type – Qwertyzw May 11 '18 at 13:39
13

I don't think forward declarations are even possible with typedef. Use of struct, enum, and union allow for forwarding declarations when dependencies (knows about) is bidirectional.

Style: Use of typedef in C++ makes quite a bit of sense. It can almost be necessary when dealing with templates that require multiple and/or variable parameters. The typedef helps keep the naming straight.

Not so in the C programming language. The use of typedef most often serves no purpose but to obfuscate the data structure usage. Since only { struct (6), enum (4), union (5) } number of keystrokes are used to declare a data type there is almost no use for the aliasing of the struct. Is that data type a union or a struct? Using the straightforward non-typdefed declaration lets you know right away what type it is.

Notice how Linux is written with strict avoidance of this aliasing nonsense typedef brings. The result is a minimalist and clean style.

Yoon5oo
  • 489
  • 5
  • 11
natersoz
  • 1,485
  • 2
  • 18
  • 27
  • 13
    Clean would be not repeating `struct`everywhere... Typedef's make new types. What do you use? Types. We don't *care* if it's a struct, union, or enum, that's why we typedef it. – GManNickG May 29 '10 at 07:14
  • 14
    No, we *do* care if it's a struct or union, versus an enum or some atomic type. You can't coerce a struct to an integer or to a pointer (or to any other type, for that matter), which is all you sometimes have to store some context. Having the 'struct' or 'union' keywords around improves locality of reasoning. Nobody says you need to know what's *inside* the struct. – Bernd Jendrissek Nov 26 '12 at 03:59
  • 3
    @BerndJendrissek: Structs and unions are different from other types, but should client code care about which of those two things (struct or union) something like a `FILE` is? – supercat Mar 27 '15 at 18:54
  • 5
    @supercat FILE is a good use of typedef. I think that typedef is *overused*, not that it's a misfeature of the language. IMHO using typedef for everything is the "speculative overgenerality" code smell. Notice that you declare variables as FILE *foo, never as FILE foo. To me, this matters. – Bernd Jendrissek Mar 29 '15 at 17:16
  • @BerndJendrissek: If file-identifying variables were of type FILE rather than `FILE*`, it would be unclear when/whether methods should use parameters of type `FILE` versus `FILE*`. In Pascal, the normal mode of usage would be to have variables of the type itself, but have methods take by-reference parameters of that type; C doesn't have by-reference parameters, though [I vaguely recall Pascal won't allow a variable of type `File` or `Text` to be passed by value, thus avoiding any ambiguity as to what such a thing should mean]. – supercat Mar 29 '15 at 17:36
  • @BerndJendrissek: BTW, I personally wonder whether union types offer any advantages, in either programmer-friendliness or compiler simplicity, versus having a means of explicitly aliasing structure members? I would think an aliasing mechanism would be simpler for a compiler to implement, and more useful for programmers, especially if bitfields were subsumed into that, e.g. `int mode_settings; unsigned mode @mode_settings.0:4; unsigned enable @mode_settings.31:1;`. I don't know if any compilers presently use `@` *within structures* in a way that would contradict that, but... – supercat Mar 29 '15 at 17:45
  • ...adding a syntax like that to the language could be helpful even today since it would provide a portable means of declaring bitfields. – supercat Mar 29 '15 at 17:48
  • 4
    @supercat: "If file-identifying variables were of type FILE rather than FILE* ..." But that's exactly the ambiguity that typedefs enable! We're just used to fopen taking a FILE * so we don't fret about it, but each time you add typedef you're introducing yet another bit of cognitive overhead: does this API want foo_t args or foo_t *? Explicitly carrying the 'struct' along improves locality of reasoning, if at the cost of a few more characters per function definition. – Bernd Jendrissek Mar 30 '15 at 18:47
  • 1
    @BerndJendrissek: A problem with carrying the `struct` notation along is that in many cases it should be possible for the implementation to use a `union` rather than a `struct` without the client code having to care. If C had omitted `union` types but instead included a means of explicitly aliasing struct fields, then that wouldn't be an issue, but as it is `struct` and `union` types are distinct. The client API should care that `FILE` isn't typedef'ed as an array (those behave weirdly) but otherwise shouldn't care what it is. – supercat Mar 30 '15 at 19:18
  • @supercat That's an interesting point, and I would agree, only that you can in theory wrap a union inside a struct, right? (A struct with a single union member) And thus you would not be changing the public interface of your new implementation. – David Callanan Dec 25 '20 at 11:04
  • @DavidCallanan: Since writing the above, I've shifted to favoring the use of `struct tag` syntax and no longer typedef structs. The deciding factor was the fact that if one has a header `widget.h` with a function `int importWidgetFromWazzle(struct widget *dest, struct wazzle *src);`, but not all clients use wazzles, use of struct-tag syntax will avoids any need to have client code include `wazzle.h`, have `wazzle.h` placed where `widget.h` can find it, or do other gymnastics. If the C had *always* specified that `typedef struct foo foo;` would be ignored if `foo` was already defined... – supercat Dec 25 '20 at 17:00
  • ...in that fashion, then the Wazzle library could specify that clients may, at their leisure, contain `typedef struct wazzle wazzle`. I think what clued me in to the usefulness of this was a freestanding implementation that includes an implementation of `fprintf` and contains `typedef struct __FILE FILE;`, but doesn't include any definition for `fwrite` nor for the structure type. User code can thus define `struct __FILE` to contain whatever members would be needed by its implementation of `fwrite`. If the Standard's `stdio.h` had used type `struct FILE*` in place of `FILE`, ... – supercat Dec 25 '20 at 17:08
  • ...that would have provided a natural way for freestanding implementations to allow user code to define their own file type that could work with `fprintf` without having to use a reserved identifier for a file tag, creating potential incompatibility between implementations that happen to choose the struct tag `__FILE` and those that happen to choose a different struct tag (e.g. `_FILE`). – supercat Dec 25 '20 at 17:11
6

Let's start with the basics and work our way up.

Here is an example of Structure definition:

struct point
  {
    int x, y;
  };

Here the name point is optional.

A Structure can be declared during its definition or after.

Declaring during definition

struct point
  {
    int x, y;
  } first_point, second_point;

Declaring after definition

struct point
  {
    int x, y;
  };
struct point first_point, second_point;

Now, carefully note the last case above; you need to write struct point to declare Structures of that type if you decide to create that type at a later point in your code.

Enter typedef. If you intend to create new Structure ( Structure is a custom data-type) at a later time in your program using the same blueprint, using typedef during its definition might be a good idea since you can save some typing moving forward.

typedef struct point
  {
    int x, y;
  } Points;

Points first_point, second_point;

A word of caution while naming your custom type

Nothing prevents you from using _t suffix at the end of your custom type name but POSIX standard reserves the use of suffix _t to denote standard library type names.

Asif
  • 410
  • 1
  • 5
  • 12
  • The `typedef point { ... } Points` is not a really good idea. Since the name `point` and `Points` have too much difference. When someone has to forward declare the `struct` for a pointer then the different name is a problem, especially when it is in a library that may change. If you use `typedef` use the same name or have a clear rule how to convert the name from the `struct` name to the `typedef` name. – 12431234123412341234123 Sep 07 '20 at 09:17
3

the name you (optionally) give the struct is called the tag name and, as has been noted, is not a type in itself. To get to the type requires the struct prefix.

GTK+ aside, I'm not sure the tagname is used anything like as commonly as a typedef to the struct type, so in C++ that is recognised and you can omit the struct keyword and use the tagname as the type name too:


    struct MyStruct
    {
      int i;
    };

    // The following is legal in C++:
    MyStruct obj;
    obj.i = 7;

philsquared
  • 21,754
  • 12
  • 64
  • 95
1

typedef will not provide a co-dependent set of data structures. This you cannot do with typdef:

struct bar;
struct foo;

struct foo {
    struct bar *b;
};

struct bar {
    struct foo *f;
};

Of course you can always add:

typedef struct foo foo_t;
typedef struct bar bar_t;

What exactly is the point of that?

natersoz
  • 1,485
  • 2
  • 18
  • 27
  • If the C Standard had always allowed repeated definitions of type names in cases where the old and new definitions match precisely, I would have favored having code which is going to use a struct type include a `typedef struct name name;` as a common practice, but of the older compilers that have proven themselves reliable don't allow such repeated definitions, and working around that restriction creates more problems than would simply using `struct tagName` as the name of the type. – supercat Dec 25 '20 at 17:25
1

A> a typdef aids in the meaning and documentation of a program by allowing creation of more meaningful synonyms for data types. In addition, they help parameterize a program against portability problems (K&R, pg147, C prog lang).

B> a structure defines a type. Structs allows convenient grouping of a collection of vars for convenience of handling (K&R, pg127, C prog lang.) as a single unit

C> typedef'ing a struct is explained in A above.

D> To me, structs are custom types or containers or collections or namespaces or complex types, whereas a typdef is just a means to create more nicknames.

JamesAD-0
  • 679
  • 6
  • 6
0

In 'C' programming language the keyword 'typedef' is used to declare a new name for some object(struct, array, function..enum type). For example, I will use a 'struct-s'. In 'C' we often declare a 'struct' outside of the 'main' function. For example:

struct complex{ int real_part, img_part }COMPLEX;

main(){

 struct KOMPLEKS number; // number type is now a struct type
 number.real_part = 3;
 number.img_part = -1;
 printf("Number: %d.%d i \n",number.real_part, number.img_part);

}

Each time I decide to use a struct type I will need this keyword 'struct 'something' 'name'.'typedef' will simply rename that type and I can use that new name in my program every time I want. So our code will be:

typedef struct complex{int real_part, img_part; }COMPLEX;
//now COMPLEX is the new name for this structure and if I want to use it without
// a keyword like in the first example 'struct complex number'.

main(){

COMPLEX number; // number is now the same type as in the first example
number.real_part = 1;
number.img)part = 5;
printf("%d %d \n", number.real_part, number.img_part);

}

If you have some local object(struct, array, valuable) that will be used in your entire program you can simply give it a name using a 'typedef'.

Yoon5oo
  • 489
  • 5
  • 11
0

Turns out in C99 typedef is required. It is outdated, but a lot of tools (ala HackRank) use c99 as its pure C implementation. And typedef is required there.

I'm not saying they should change (maybe have two C options) if the requirement changed, those of us studing for interviews on the site would be SOL.

  • 2
    "Turns out in C99 `typedef` is required." What do you mean? – Julien Lopez Nov 02 '16 at 09:54
  • The question is about `C`, not `C++`. In `C` typedefs are 'required' (and will most likely always be). 'Required' as in, you will not be able to declare a variable `Point varName;` and have the type be synonymous with `struct Point;` without a `typedef struct Point Point;`. – yyny Nov 30 '16 at 21:26
-3

At all, in C language, struct/union/enum are macro instruction processed by the C language preprocessor (do not mistake with the preprocessor that treat "#include" and other)

so :

struct a
{
   int i;
};

struct b
{
   struct a;
   int i;
   int j;
};

struct b is expended as something like this :

struct b
{
    struct a
    {
        int i;
    };
    int i;
    int j;
}

and so, at compile time it evolve on stack as something like: b: int ai int i int j

that also why it's dificult to have selfreferent structs, C preprocessor round in a déclaration loop that can't terminate.

typedef are type specifier, that means only C compiler process it and it can do like he want for optimise assembler code implementation. It also dont expend member of type par stupidly like préprocessor do with structs but use more complex reference construction algorithm, so construction like :

typedef struct a A; //anticipated declaration for member declaration

typedef struct a //Implemented declaration
{
    A* b; // member declaration
}A;

is permited and fully functional. This implementation give also access to compilator type conversion and remove some bugging effects when execution thread leave the application field of initialisation functions.

This mean that in C typedefs are more near as C++ class than lonely structs.

doccpu
  • 19
  • 1
  • 4
    It isn't difficult to have self-referential structs at all. struct foo { struct foo *next; int thing; } – Bernd Jendrissek Mar 30 '15 at 18:52
  • 5
    ...what? Saying _preprocessor_ to describe the resolution of `structs` and `typedef`s is bad enough, but the rest of your writing is so confusing that I find it hard to get any message from it. One thing I can say, though, is that your idea that a non-`typedef`d `struct` cannot be forward-declared or used as an opaque (pointer) member is totally false. In your 1st example, `struct b` can trivially contain a `struct a *`, no `typedef` required. The assertions that `struct`s are merely dumb pieces of macro-expansion, and that `typedef`s give them revolutionary new powers, are painfully incorrect – underscore_d Apr 09 '16 at 16:44