tags:

views:

370

answers:

5

I encountered some code reading

typedef enum eEnum { c1, c2 } tagEnum;

typedef struct { int i; double d; } tagMyStruct;

I heard rumours that these constructs date from C. In C++ you can easily write

enum eEnum { c1, c2 };
struct MyStruct { int i; double d; };

Is that true? When do you need the first variant?

+1  A: 

It's just shorthand.

In the second instance, to declare the struct you'd do so with:

struct MyStruct a;

In the first variant, you'd do so with:

tagMyStruct a;
Phil
It's shorthand in C, too? Or do you refer to C++ only?
xtofl
A: 

The second variant also exists in C.

You use the first variant whenever you want to name your type, e.g.:

tagEnum myFunc(tagMyStruct * myArg);
mouviciel
A: 

The first one may be inconvenient in C++, as you cannot forward declare it in a header file.

LK
+10  A: 

In C, if you were to write

struct MyStruct { int i; double d; };

whenever you wanted to reference that type, you'd have to specify that you were talking about a struct:

struct MyStruct instanceOfMyStruct;
struct MyStruct *ptrToMyStruct;

With the typedef version:

typedef struct { int i; double d; } tagMyStruct;

you only have to write:

tagMyStruct instanceOfMyStruct;
tagMyStruct *ptrToMyStruct;

The other big advantage with the typedef'd version is that you can refer to the struct the same way in both C and C++, whereas in the second version they are refered to differently in C than in C++.

Eclipse
would the "only have to write" version be "tagMyStruct ..." iso "MyStruct"? Or is this correct? (it's counterintuitive...)
xtofl
+9  A: 

First, both declarations are legal in both C and C++. However, in C, they have slightly different semantics. (In particular, the way you refer to the struct later varies).

The key concept to understand is that in C, structs exist in a separate namespace. All built-in types, as well as typedefs exist in the "default" namespace. That is, when I type int, the compiler only checks this "default" namespace. If I type "tagMyStruct" as in your example, the compiler also only checks this one namespace. But depending which type of declaration you use, the struct may not exist in that namespace.

Structs are different, and exist in a separate namespace. So if I make the following declaration:

struct mystruct {};

I can not simply refer to it as mystruct. Instead, I have to specify that I want the mystruct which exists in the struct namespace:

void foo(struct mystruct bar); // Declare a function which takes a mystruct as its parameter

Which gets a bit verbose and awkward in the long run. Instead, you can typedef it into the default namespace:

typedef struct mystruct mystruct; // From now on, 'mystruct' in the normal namespace is an alias for 'mystruct' in the struct namespace

and now, my function can be declared in the straightforward way:

void foo(mystruct bar);

So your first example simply merges these two steps together: Declare a struct, and put an alias into the regular namespace. And of course, since we're typedeffing it anyway, we don't need the "original" name, so we can make the struct anonymous. So after your declaration

typedef struct { int i; double d; } tagMyStruct;

we have a struct with no name, which has been typedef'ed to 'tagMyStruct' in the default namespace.

That's how C treats it. Both types of declarations are valid, but one does not create the alias in the "default" namespace, so you have to use the struct keyword every time you refer to the type.

In C++, the separate struct namespace doesn't exist, so they mean the same thing. (but the shorter version is preferred).

Edit Just to be clear, no, C does not have namespaces. Not in the usual sense. C simply places identifiers into one of two predefined namespaces. The names of structs (and enums, as I recall) are placed in one, and all other identifiers in another. Technically, these are namespaces because they are separate "containers" in which names are placed to avoid conflicts, but they are certainly not namespaces in the C++/C# sense.

jalf
Nice explanation
Eclipse
So C _does_ have namespaces! :) Thanks, that clarifies many things.
xtofl
xtofl: No, not really. Not in the C++ sense. structs and built-in types exist in separate namespaces, but beyond that, no. You can't declare new namespaces, or anything else you'd expect. So this is a bit of a special case. It's probably a bad idea to think of it as "C has namespaces" ;)
jalf
Point being that "namespace" was a perfectly cromulent word, before C++ used it to refer to its own particular concept of user-defined namespaces. You could likewise say that the C preprocessor adds another namespace (for macros), distinct from the spaces where C keeps its names.
Steve Jessop
I wouldn't blame C++ for that. But yes, namespace certainly has a more basic meaning than the C++ implementation In the end, it's just the ability to distinguish between identical names, by storing them in separate "spaces", and that concept exists in most languages in some form.
jalf
Don't forget about union tags too. They share the same namespace as struct tags - you can't have both 'union u { ... }' and 'struct u { ... }' in the same scope.
Jonathan Leffler