首先,这两种声明在 C 和 C++ 中都是合法的。但是,在 C 中,它们的语义略有不同。 (特别是,您稍后引用该结构的方式会有所不同)。
要理解的关键概念是,在 C 中,结构存在于单独的命名空间中。
所有内置类型以及 typedef 都存在于“默认”命名空间中。也就是说,当我键入int 时,编译器只检查这个“默认”命名空间。如果我在您的示例中键入“tagMyStruct”,编译器也只检查这个命名空间。但根据您使用的声明类型,该结构可能不存在于该命名空间中。
结构是不同的,存在于单独的命名空间中。因此,如果我做出以下声明:
struct mystruct {};
我可以不简单地将其称为 mystruct。相反,我必须指定我想要存在于 struct 命名空间中的 mystruct:
void foo(struct mystruct bar); // Declare a function which takes a mystruct as its parameter
从长远来看,这会变得有点冗长和尴尬。相反,您可以将其 typedef 到默认命名空间中:
typedef struct mystruct mystruct; // From now on, 'mystruct' in the normal namespace is an alias for 'mystruct' in the struct namespace
现在,我的函数可以直接声明:
void foo(mystruct bar);
所以您的第一个示例只是将这两个步骤合并在一起:声明一个结构,并将一个别名放入常规命名空间。当然,由于我们无论如何都要对它进行类型定义,我们不需要“原始”名称,因此我们可以使结构匿名。所以在你的声明之后
typedef struct { int i; double d; } tagMyStruct;
我们有一个没有名称的结构,它在默认命名空间中已被类型定义为“tagMyStruct”。
C 就是这样对待它的。这两种类型的声明都是有效的,但一种不会在“默认”命名空间中创建别名,因此每次引用该类型时都必须使用 struct 关键字。
在 C++ 中,不存在单独的结构命名空间,因此它们的含义相同。 (但首选较短的版本)。
编辑 明确一点,不,C 没有命名空间。不是通常意义上的。
C 只是将标识符放入两个预定义的命名空间之一。结构(和枚举,我记得)的名称放在一个中,所有其他标识符放在另一个中。从技术上讲,它们是命名空间,因为它们是单独的“容器”,其中放置名称以避免冲突,但它们肯定不是 C++/C# 意义上的命名空间。