What are the differences between these two typedef styles in C? What are the differences between these two typedef styles in C? objective-c objective-c

What are the differences between these two typedef styles in C?


The difference is that the second approach declares a type named enum SomeEnum and also declares a typedef-name SomeEnum - an alias for that type. It can actually be combined into the equivalent one-liner

typedef enum SomeEnum { first, second, third } SomeEnum;

which makes it rather obvious that the only difference between the two approaches is whether there's a name after the enum keyword. With the second approach, you can declare object of that enum type by using either SomeEnum e or enum SomeEnum e, whichever you prefer.

The first approach only declares the typedef-name SomeEnum for an originally anonymous enum type, meaning that you are limited to SomeEnum e declarations.

So, as long as you only use the typedef-name SomeEnum in your declarations, there will be no difference between the two. However, in some cases you might have to use the full original name of the type enum SomeEnum. In the first approach that name is not available, so you'll be out of luck.

For example, if after the above declaration you also declare a variable named SomeEnum in some nested scope

int SomeEnum;

the name of the variable will hide the typedef-name of the enum, thus making this declaration illegal

SomeEnum e; /* ERROR: `SomeEnum` is not a type */

However, if you used the second approach when declaring your enum, you can work around this problem by using the full type name

enum SomeEnum e; /* OK */

This would not be possible if you used the first approach when declaring your enum type.

When used with structs, the name after the struct is a must when you need a self-referencing type (a type that contains a pointer to the same type), like

typedef struct SomeStruct {  struct SomeStruct *next;} SomeStruct;

Finally, in the second approach the typedef name is totally optional. You can simply declare

enum SomeEnum { first, second, third };

and just use enum SomeEnum every time you need to refer to this type.


Yes, there is a semantic difference. The second snippet declares a tag identifier, but the first doesn't. Both declare an ordinary identifier.

That means that for the first, this code is not valid, but for the second, it is:

enum SomeEnum foo;

As far as i know, there is no other semantic difference between them in your code. For structs and unions, the second form, maybe combined with the typedef in one declaration, is needed for recursive types

typedef struct node {  struct node *parent; // refer to the tag identifier} node;

The ordinary identifier is not yet visible in the struct's specifier, and thus you need to refer to the struct by the already declared tag identifier. Tag identifiers are referred to by prepending them by "struct", "union" or "enum", while ordinary identifiers are referred to without a prefix (thus the name "ordinary").

Besides separating the identifiers that refer to structs, unions and enumerations from those that refer to values, tag identifiers are also useful for creating forward declarations:

/* forward declaration */struct foo; /* for pointers, forward declarations are entirely sufficient */struct foo *pfoo = ...;/* ... and then later define its contents */struct foo {  /* ... */};

Typedef names can't be declared repeatedly at the same scope (as opposed to C++ where they can), and they need to refer to an existing type, so that they cannot be used to create forward declarations.


The only real difference is that in the second case, you can use something like:

enum SomeEnum x;

whereas the first only supports:

SomeEnum x;

To people who've been writing C a long time, defining a struct without the struct keyword often "feels" strange...