typedef enum eEnum { c1, c2 } tagEnum;
typedef struct { int i; double d; } tagMyStruct;
我听说这些结构体起源于C语言。在C++中,你可以轻松地编写:
enum eEnum { c1, c2 };
struct MyStruct { int i; double d; };
这是真的吗?第一个版本什么时候需要?
首先,在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,我们不需要“原始”名称,因此我们可以使结构体成为匿名的。所以在你的声明之后。
typedef struct { int i; double d; } tagMyStruct;
我们有一个没有名称的结构体,在默认命名空间中,它已被typedef为'tagMyStruct'。
这是C的处理方法。这两种声明方式都是有效的,但其中一种不会在“默认”命名空间中创建别名,因此每次引用该类型时都必须使用struct关键字。
在C ++中,独立的结构体命名空间不存在,所以它们意思相同。(但较短的版本更受欢迎)。
编辑:为了清楚起见,C并没有命名空间。不是通常意义下的。C只是将标识符放入两个预定义的命名空间之一。结构体(和枚举,据我所知)的名称被放置在其中一个命名空间中,而所有其他标识符则放置在另一个命名空间中。从技术上讲,这些是命名空间,因为它们是放置名称以避免冲突的单独的“容器”,但它们当然不是C ++ / C#中的命名空间。
在C语言中,如果你要写下如下代码:
struct MyStruct { int i; double d; };
无论何时你想引用该类型,你必须指定你正在谈论一个结构体:struct MyStruct instanceOfMyStruct;
struct MyStruct *ptrToMyStruct;
使用typedef版本:
typedef struct { int i; double d; } tagMyStruct;
你只需要写:
tagMyStruct instanceOfMyStruct;
tagMyStruct *ptrToMyStruct;
使用typedef的版本的另一个重要优点是,您可以在C和C++中以相同的方式引用结构体,而在第二个版本中,在C中和C++中引用它们的方式不同。
这只是速记。
在第二个实例中,要声明结构体,您可以使用以下代码:
struct MyStruct a;
tagMyStruct a;
tagEnum myFunc(tagMyStruct * myArg);
第一种方法在C++中可能不太方便,因为您无法在头文件中进行前向声明。