An important difference between a 'typedef struct' and a 'struct' in C++ is that inline member initialisation in 'typedef structs' will not work.
// the 'x' in this struct will NOT be initialised to zero
typedef struct { int x = 0; } Foo;
// the 'x' in this struct WILL be initialised to zero
struct Foo { int x = 0; };
In C++, there is only a subtle difference. It's a holdover from C, in which it makes a difference.
The C language standard (C89 §3.1.2.3, C99 §6.2.3, and C11 §6.2.3) mandates separate namespaces for different categories of identifiers, including tag identifiers (for struct/union/enum) and ordinary identifiers (for typedef and other identifiers).
If you just said:
struct Foo { ... };
Foo x;
you would get a compiler error, because Foo is only defined in the tag namespace.
You'd have to declare it as:
struct Foo x;
Any time you want to refer to a Foo, you'd always have to call it a struct Foo. This gets annoying fast, so you can add a typedef:
struct Foo { ... };
typedef struct Foo Foo;
Now struct Foo (in the tag namespace) and just plain Foo (in the ordinary identifier namespace) both refer to the same thing, and you can freely declare objects of type Foo without the struct keyword.
The construct:
typedef struct Foo { ... } Foo;
is just an abbreviation for the declaration and typedef.
Finally,
typedef struct { ... } Foo;
declares an anonymous structure and creates a typedef for it. Thus, with this construct, it doesn't have a name in the tag namespace, only a name in the typedef namespace. This means it also cannot be forward-declared. If you want to make a forward declaration, you have to give it a name in the tag namespace.
In C++, all struct/union/enum/class declarations act like they are implicitly typedef'ed, as long as the name is not hidden by another declaration with the same name. See Michael Burr's answer for the full details.
One more important difference: typedefs cannot be forward declared. So for the typedef option you must #include the file containing the typedef, meaning everything that #includes your .h also includes that file whether it directly needs it or not, and so on. It can definitely impact your build times on larger projects.
Without the typedef, in some cases you can just add a forward declaration of struct Foo; at the top of your .h file, and only #include the struct definition in your .cpp file.
There is a difference, but subtle. Look at it this way: struct Foo introduces a new type. The second one creates an alias called Foo (and not a new type) for an unnamed struct type.
7.1.3 The typedef specifier
1 [...]
A name declared with the typedef specifier becomes a typedef-name. Within the scope of its declaration, a
typedef-name is syntactically equivalent to a keyword and names the type associated with the identifier in
the way described in Clause 8. A typedef-name is thus a synonym for another type. A typedef-name does not introduce a new type the way a class declaration (9.1) or enum declaration does.
8 If the typedef declaration defines an unnamed class (or enum), the first typedef-name declared by the declaration
to be that class type (or enum type) is used to denote the class type (or enum type) for linkage
purposes only (3.5). [ Example:
typedef struct { } *ps, S; // S is the class name for linkage purposes
So, a typedef always is used as an placeholder/synonym for another type.
An important difference between a 'typedef struct' and a 'struct' in C++ is that inline member initialisation in 'typedef structs' will not work.
In C++, there is only a subtle difference. It's a holdover from C, in which it makes a difference.
The C language standard (C89 §3.1.2.3, C99 §6.2.3, and C11 §6.2.3) mandates separate namespaces for different categories of identifiers, including tag identifiers (for
struct
/union
/enum
) and ordinary identifiers (fortypedef
and other identifiers).If you just said:
you would get a compiler error, because
Foo
is only defined in the tag namespace.You'd have to declare it as:
Any time you want to refer to a
Foo
, you'd always have to call it astruct Foo
. This gets annoying fast, so you can add atypedef
:Now
struct Foo
(in the tag namespace) and just plainFoo
(in the ordinary identifier namespace) both refer to the same thing, and you can freely declare objects of typeFoo
without thestruct
keyword.The construct:
is just an abbreviation for the declaration and
typedef
.Finally,
declares an anonymous structure and creates a
typedef
for it. Thus, with this construct, it doesn't have a name in the tag namespace, only a name in the typedef namespace. This means it also cannot be forward-declared. If you want to make a forward declaration, you have to give it a name in the tag namespace.In C++, all
struct
/union
/enum
/class
declarations act like they are implicitlytypedef
'ed, as long as the name is not hidden by another declaration with the same name. See Michael Burr's answer for the full details.There is no difference in C++, but I believe in C it would allow you to declare instances of the struct Foo without explicitly doing:
One more important difference:
typedef
s cannot be forward declared. So for thetypedef
option you must#include
the file containing thetypedef
, meaning everything that#include
s your.h
also includes that file whether it directly needs it or not, and so on. It can definitely impact your build times on larger projects.Without the
typedef
, in some cases you can just add a forward declaration ofstruct Foo;
at the top of your.h
file, and only#include
the struct definition in your.cpp
file.There is a difference, but subtle. Look at it this way:
struct Foo
introduces a new type. The second one creates an alias called Foo (and not a new type) for an unnamedstruct
type.So, a typedef always is used as an placeholder/synonym for another type.
You can't use forward declaration with the typedef struct.
The struct itself is an anonymous type, so you don't have an actual name to forward declare.
A forward declaration like this wont work: