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.