193

I haven't written any C++ in years and now I'm trying to get back into it. I then ran across this and thought about giving up:

typedef enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

What is this? Why is the typedef keyword used here? Why does the name TokenType appear twice in this declaration? How are the semantics different from this:

enum TokenType
{
    blah1 = 0x00000000,
    blah2=0x01000000,
    blah3=0x02000000
};
Keith Pinson
  • 7,162
  • 5
  • 54
  • 97
Tim Merrifield
  • 5,348
  • 5
  • 27
  • 32

9 Answers9

160

In C, declaring your enum the first way allows you to use it like so:

TokenType my_type;

If you use the second style, you'll be forced to declare your variable like this:

enum TokenType my_type;

As mentioned by others, this doesn't make a difference in C++. My guess is that either the person who wrote this is a C programmer at heart, or you're compiling C code as C++. Either way, it won't affect the behaviour of your code.

Ryan Fox
  • 9,416
  • 5
  • 34
  • 48
  • 14
    Your question is correct only for C, but not C++. In C++ enums and structs can be used directly as if there was a typedef. – David Rodríguez - dribeas Dec 21 '08 at 22:06
  • 7
    Well, yes but this does answer the real question that was asked which was really about "what does this even mean?" – BobbyShaftoe Dec 21 '08 at 22:08
  • So is this technically a typedef or an enum? – Miek Mar 26 '12 at 17:14
  • 5
    It's both. You could also say: enum TokenType_ { ... }; typedef enum TokenType_ TokenType; – Ryan Fox Mar 27 '12 at 16:25
  • The answer is complete, but I believe the point is that the TokenType; after the enum declaration is what is declaring the type name. So the answer is not 100% complete Declaring 'the first way' specifies BOTH an enum and a new typename that is that enum in one blob of syntax. So the answer was helpful, but I'm thinking could be improved a bit. Maybe I was too harsh to down vote. So I upvoted it after all that. If I was really sure of myself, I'd take a swag at editing/improving the answer... but this is a pretty good answ – Ross Youngblood Feb 18 '19 at 22:16
  • The only thing I would add to the answer is that you don't need to name your enum if you use typedef. Something like `typedef enum { blah1 = 0x00000000, blah2 = 0X01000000, blah3 = 0X02000000 } TokenType;` works just fine as well with most C and C++ compilers. – mrKirushko Apr 07 '21 at 12:56
105

It's a C heritage, in C, if you do :

enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
};

you'll have to use it doing something like :

enum TokenType foo;

But if you do this :

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

You'll be able to declare :

TokenType foo;

But in C++, you can use only the former definition and use it as if it were in a C typedef.

Michael Morris
  • 168
  • 2
  • 13
mat
  • 11,864
  • 5
  • 37
  • 44
21

You do not need to do it. In C (not C++) you were required to use enum Enumname to refer to a data element of the enumerated type. To simplify it you were allowed to typedef it to a single name data type.

typedef enum MyEnum { 
  //...
} MyEnum;

allowed functions taking a parameter of the enum to be defined as

void f( MyEnum x )

instead of the longer

void f( enum MyEnum x )

Note that the name of the typename does not need to be equal to the name of the enum. The same happens with structs.

In C++, on the other hand, it is not required, as enums, classes and structs can be accessed directly as types by their names.

// C++
enum MyEnum {
   // ...
};
void f( MyEnum x ); // Correct C++, Error in C
David Rodríguez - dribeas
  • 192,922
  • 20
  • 275
  • 473
11

In C, it is good style because you can change the type to something besides an enum.

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

foo(enum e_TokenType token);  /* this can only be passed as an enum */

foo(TokenType token); /* TokenType can be defined to something else later
                         without changing this declaration */

In C++ you can define the enum so that it will compile as C++ or C.

BeWarned
  • 2,212
  • 1
  • 15
  • 22
  • Don't you mean to say `In C++ you can *typedef* the enum so that it will compile as C++ or C.`? You said: `In C++ you can define the enum so that it will compile as C++ or C.` Notice how I changed your `define` to `typedef`. Well...I suppose `typedef`ing *is* defining. – Gabriel Staples Oct 25 '19 at 04:39
7

Holdover from C.

Tim
  • 19,558
  • 22
  • 111
  • 208
  • Dunno that the 'early' qualifier is relevant; you would still write that in C if you wanted to use the type name without the enum prefix. – Jonathan Leffler Dec 21 '08 at 22:31
  • 1
    true. I will delete it. I have not followed the C spec for a long long time. I was too lazy to check the c/c++ distinction... -1 for me. – Tim Dec 22 '08 at 00:09
7

Some people say C doesn't have namespaces but that is not technically correct. It has three:

  1. Tags (enum, union, and struct)
  2. Labels
  3. (everything else)

typedef enum { } XYZ; declares an anonymous enumeration and imports it into the global namespace with the name XYZ.

typedef enum ABC { } XYZ; declares an enum named ABC in the tag namespace, then imports it into the global namespace as XYZ.

Some people don't want to bother with the separate namespaces so they typedef everything. Others never typedef because they want the namespacing.

russbishop
  • 14,900
  • 6
  • 54
  • 71
  • This isn't exactly accurate. structs, unions, and enums are referenced by tag name (unless anonymous, as you mentioned). There are separate namespaces for types and tags. You can have a type with the exact same name as a tag and compile fine. However, if an enum has the same tag as a struct, this is a compile error exactly as 2 structs or 2 enums with the same tag would be. Your also forgetting that labels for goto are a separate namespace. A label could be the same name as a tag, or an identifier, but not a type, and an identifier can have the same name as a tag, but not a type. – Rich Jahn Jul 04 '18 at 17:40
3

This is kind of old, but anyway, I hope you'll appreciate the link that I am about to type as I appreciated it when I came across it earlier this year.

Here it is. I should quote the explanation that is always in my mind when I have to grasp some nasty typedefs:

In variable declarations, the introduced names are instances of the corresponding types. [...] However, when the typedef keyword precedes the declaration, the introduced names are aliases of the corresponding types

As many people previously said, there is no need to use typedefs declaring enums in C++. But that's the explanation of the typedef's syntax! I hope it helps (Probably not OP, since it's been almost 10 years, but anyone that is struggling to understand these kind of things).

orlandini
  • 103
  • 6
1

In some C codestyle guide the typedef version is said to be preferred for "clarity" and "simplicity". I disagree, because the typedef obfuscates the real nature of the declared object. In fact, I don't use typedefs because when declaring a C variable I want to be clear about what the object actually is. This choice helps myself to remember faster what an old piece of code actually does, and will help others when maintaining the code in the future.

AdRiX
  • 69
  • 1
  • 1
  • 8
1

The actual answer to the "why" question (which is surprisingly ignored by the existing answers top this old question) is that this enum declaration is probably located in a header file that is intended to be cross-compilable as both C and C++ code (i.e. included into both C and C++ implementation fiules). The art of writing such header files relies on the author's ability to select language features that have the proper compatible meaning in both languages.

AnT
  • 291,388
  • 39
  • 487
  • 734