By criddell


2009-03-04 20:41:12 8 Comments

In C++, is there any difference between:

struct Foo { ... };

and

typedef struct { ... } Foo;

8 comments

@Adam Rosenfield 2009-03-04 20:45:36

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.

@dirkgently 2009-03-04 20:51:13

While what you say is true, AFAIK, the statement, 'typedef struct { ... } Foo;' creates an alias for an unnamed struct.

@Adam Rosenfield 2009-03-04 21:00:06

Good catch, there's a subtle difference between "typedef struct Foo { ... } Foo;" and "typedef struct { ... } Foo;".

@Jonathan Leffler 2009-06-11 04:28:50

In C, the struct tags, union tags and enumeration tags share one namespace, rather than (struct and union) using two as claimed above; the namespace referenced for typedef names is indeed separate. That means you can't have both 'union x { ... };' and 'struct x { ... };' in a single scope.

@Steve Jessop 2009-11-22 02:45:33

Aside from the not-quite-typedef thing, another difference between the two pieces of code in the question is that Foo can define a constructor in the first example, but not in the second (since anonymous classes can't define constructors or destructors).

@Lazer 2010-03-13 06:43:06

@Adam Rosenfield: "In C++, there is no difference", is it because there are no separate tag and typedef namespaces in C++?

@Fred Nurk 2011-02-07 20:49:22

@Lazer: There are subtle differences, but Adam means (as he goes on to say) that you can use 'Type var' to declare variables without a typedef.

@Mr.Anubis 2012-04-05 10:01:50

Can you please say what is tag namespace and where it start and ends?

@Florin Stingaciu 2012-10-25 16:33:45

@AdamRosenfield I quoted part of your explanation here. You deserve the credit. Great answer!

@sellibitze 2012-10-30 11:59:55

IIRC I had some troubles using anonymous structs as template arguments. So, if one wants to write a header that is meant for C as well as C++ compilers, where you use the types as template arguments in C++, the struct should have a name.

@ovgolovin 2012-11-08 19:42:23

What about typedef struct Foo {...}? I've just come across this declaration here (typedef struct nodeStructure). It seems to me that typedef here has no use, as later in the code nodeStructure is used with struct keyword.

@Rich 2014-03-15 18:09:48

I am a bit confused after reading all the posts regarding this question. Could you explain some of my questions here? I am sure Ben is correct. I am just trying to get more inputs here. Thanks!

@Tomáš Zato 2015-08-30 23:07:39

How to predefine struct with typedef WITHOUT declaring it? I want just typedef struct Foo and later on in the code I'll write struct Foo {...}.

@alfC 2016-08-17 19:16:37

Does this difference between "namespaces" in C and C++ (implicit typedef) creates a backwards incompatibility between C++ and C?

@Adam Rosenfield 2016-08-18 00:19:30

@Jonathan Leffler 2016-12-09 20:02:44

@Mr.Anubis: the tag namespace is the list of tags used with struct tag or union tag or enum tag. The namespace starts at the beginning of the translation unit (TU) and ends at the end of the TU. It is scoped so declarations inside { … } override declarations outside.

@Yasin Yousif 2017-12-17 05:26:42

ok , for a typedef struct _Foo_ { float x} Foo; i.e can tag and ordinary namscape have different names or the underscore doesn't matter?

@David Tu 2017-04-08 03:06:14

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

@Winter 2017-07-05 18:28:43

You did not understand the question.

@user2796283 2016-04-11 13:26:25

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

@Colin D Bennett 2016-07-29 16:24:40

Not true. In both cases x is initialized. See test in the Coliru online IDE (I initialized it to 42 so it's more obvious than with zero that the assignment has really taken place).

@user2796283 2016-07-30 20:59:10

Actually, I tested it in Visual Studio 2013 and it was not initialized. This was a problem we came across in production code. All compilers are different and only have to meet certain criteria.

@Michael Burr 2009-03-04 21:19:37

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.

@Johannes Schaub - litb 2009-07-05 21:36:27

In case you try "class foo()" and it fails: In ISO C++, "class foo()" is an illegal construct (the article was written '97, before standardization, it seems). You can put "typedef class foo foo;" into main, then you can say "foo();" (because then, the typedef-name is lexically closer than the function's name). Syntactically, in T(), T must be a simple-type-specifier. elaborated type specifiers are not allowed. Still this is a good answer, of course.

@Prasoon Saurav 2010-10-13 17:05:19

Listing 1 and Listing 2 links are broken. Have a look.

@zstewart 2017-05-09 16:34:15

If you use different naming conventions for classes and functions, you also avoid the naming conflict without needing to add extra typedefs.

@Joe 2009-03-04 20:54:25

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.

@Rich 2014-03-12 17:21:52

Why does exposing the definition of struct impact the build time? Does the compiler do extra checking even if it needs not to (given the typedef option, so that the compiler knows the definition) when it sees something like Foo* nextFoo;?

@Joe 2014-03-12 20:02:19

Its not really extra checking, its just more code that the compiler needs to deal with. For every cpp file that encounters that typedef somewhere in its include chain, its compiling the typedef. In larger projects the .h file containing the typedef could easily end up being compiled hundreds of times, although precompiled headers helps a lot. If you can get away with using a forward declaration, then its easier to limit inclusion of the .h containing the full struct specification to only the code that really cares, and therefore the corresponding include file is compiled less often.

@Rich 2014-03-13 16:43:50

please @ the previous commenter(other than the owner of the post). I almost missed ur reply. But thanks for the info.

@michaelmeyer 2015-09-13 16:13:24

This is not true anymore in C11, where can you can typedef the same struct with the same name several times.

@Yochai Timmer 2013-08-05 09:18:39

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

@Rich 2014-03-12 17:30:41

I don't get the second error for the function prototype. Why does it say "redefinition; different basic types"? the compiler does not need to know what myStruct's definition looks like, right? No matter taken from with piece of code (the typedef one, or the forward declaration one), myStruct denotes a struct type, right?

@Yochai Timmer 2014-03-13 07:48:43

@Rich It's complaining that there is a conflict of names. There's a forward declaration saying "look for a struct called myStruct" and then there's the typedef which is renaming a nameless structure as "myStruct".

@Rich 2014-03-13 08:07:49

You mean put both typedef and forward declaration in the same file? I did, and gcc compiled it fine. myStruct is correctly interpreted as the nameless structure. Tag myStruct lives in tag namespace and typedef_ed myStruct lives in the normal namespace where other identifiers like function name, local variable names live in. So there should not be any conflict..I can show you my code if you doubt there is any error in it.

@Yochai Timmer 2014-03-13 08:15:38

@Rich GCC gives the same error, text varies a bit: gcc.godbolt.org/…

@Rich 2014-03-13 08:23:56

I think I understand that when you only have a typedef, forward declaration with the typedefed name, does not refer to the unnamed structure. Instead the forward declaration declares an incomplete structure with tag myStruct. Also, without seeing the definition of typedef, the function prototype using the typedefed name is not legal. Thus we have to include the whole typedef whenever we need to use myStruct to denote a type. Correct me if I misunderstood u. Thanks.

@Rich 2014-03-13 08:31:15

I think ur code is compiled with g++ instead of gcc. In C++, this is definitely not allowed. As in C++, structure name is implicitly typedefed. But if you try gcc, it compiles fine.

@dirkgently 2009-03-04 20:49:16

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.

@xian 2009-03-04 20:44:20

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;

@Keith Pinson 2012-09-05 17:51:45

Look at @dirkgently's answer---there is a difference, but it's subtle.

Related Questions

Sponsored Content

1 Answered Questions

[SOLVED] The Definitive C++ Book Guide and List

  • 2008-12-23 05:23:56
  • grepsedawk
  • 2183120 View
  • 4248 Score
  • 1 Answer
  • Tags:   c++ c++-faq

36 Answered Questions

27 Answered Questions

30 Answered Questions

[SOLVED] What are the differences between struct and class in C++?

21 Answered Questions

[SOLVED] What is the "-->" operator in C++?

5 Answered Questions

[SOLVED] What is the difference between 'typedef' and 'using' in C++11?

7 Answered Questions

12 Answered Questions

[SOLVED] typedef struct vs struct definitions

  • 2009-11-04 17:21:57
  • user69514
  • 627902 View
  • 742 Score
  • 12 Answer
  • Tags:   c struct typedef

18 Answered Questions

[SOLVED] What's the difference between struct and class in .NET?

15 Answered Questions

Sponsored Content