Difference between 'struct' and 'typedef struct' in C++?

C++StructTypedef

C++ Problem Overview


In C++, is there any difference between:

struct Foo { ... };

and:

typedef struct { ... } Foo;

C++ Solutions


Solution 1 - C++

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.

Solution 2 - C++

In this DDJ article, Dan Saks explains one small area where bugs can creep through if you do not typedef your structs (and classes!):

> If you want, you can imagine that C++ > generates a typedef for every tag > name, such as > > typedef class string string; > > Unfortunately, this is not entirely > accurate. I wish it were that simple, > but it's not. C++ can't generate such > typedefs for structs, unions, or enums > without introducing incompatibilities > with C. > > For example, suppose a C program > declares both a function and a struct > named status: > > int status(); struct status; > > Again, this may be bad practice, but > it is C. In this program, status (by > itself) refers to the function; struct > status refers to the type. > > If C++ did automatically generate > typedefs for tags, then when you > compiled this program as C++, the > compiler would generate: > > typedef struct status status; > > Unfortunately, this type name would > conflict with the function name, and > the program would not compile. That's > why C++ can't simply generate a > typedef for each tag. > > In C++, tags act just like typedef > names, except that a program can > declare an object, function, or > enumerator with the same name and the > same scope as a tag. In that case, the > object, function, or enumerator name > hides the tag name. The program can > refer to the tag name only by using > the keyword class, struct, union, or > enum (as appropriate) in front of the > tag name. A type name consisting of > one of these keywords followed by a > tag is an elaborated-type-specifier. > For instance, struct status and enum > month are elaborated-type-specifiers. > > Thus, a C program that contains both: > > int status(); struct status; > > behaves the same when compiled as C++. > The name status alone refers to the > function. The program can refer to the > type only by using the > elaborated-type-specifier struct > status. > > So how does this allow bugs to creep > into programs? Consider the program in > Listing 1. This program defines a > class foo with a default constructor, > and a conversion operator that > converts a foo object to char const *. > The expression > > p = foo(); > > in main should construct a foo object > and apply the conversion operator. The > subsequent output statement > > cout << p << '\n'; > > should display class foo, but it > doesn't. It displays function foo. > > This surprising result occurs because > the program includes header lib.h > shown in Listing 2. This header > defines a function also named foo. The > function name foo hides the class name > foo, so the reference to foo in main > refers to the function, not the class. > main can refer to the class only by > using an elaborated-type-specifier, as > in > > p = class foo(); > > The way to avoid such confusion > throughout the program is to add the > following typedef for the class name > foo: > > typedef class foo foo; > > immediately before or after the class > definition. This typedef causes a > conflict between the type name foo and > the function name foo (from the > library) that will trigger a > compile-time error. > > I know of no one who actually writes > these typedefs as a matter of course. > It requires a lot of discipline. Since > the incidence of errors such as the > one in Listing 1 is probably pretty > small, you many never run afoul of > this problem. But if an error in your > software might cause bodily injury, > then you should write the typedefs no > matter how unlikely the error. > > I can't imagine why anyone would ever > want to hide a class name with a > function or object name in the same > scope as the class. The hiding rules > in C were a mistake, and they should > not have been extended to classes in > C++. Indeed, you can correct the > mistake, but it requires extra > programming discipline and effort that > should not be necessary.

Solution 3 - C++

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.

Solution 4 - C++

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.

Solution 5 - C++

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.

typedef struct{
    int one;
    int two;
}myStruct;

A forward declaration like this wont work:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types

Solution 6 - C++

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; };

Solution 7 - C++

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:

struct Foo bar;

Solution 8 - C++

Struct is to create a data type. The typedef is to set a nickname for a data type.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncriddellView Question on Stackoverflow
Solution 1 - C++Adam RosenfieldView Answer on Stackoverflow
Solution 2 - C++Michael BurrView Answer on Stackoverflow
Solution 3 - C++JoeView Answer on Stackoverflow
Solution 4 - C++dirkgentlyView Answer on Stackoverflow
Solution 5 - C++Yochai TimmerView Answer on Stackoverflow
Solution 6 - C++user2796283View Answer on Stackoverflow
Solution 7 - C++xianView Answer on Stackoverflow
Solution 8 - C++David TuView Answer on Stackoverflow