我遇到了一些代码阅读
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; };
这是真的吗?你什么时候需要第一个变体?
答案 0 :(得分:10)
在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'd版本的另一大优势是你可以在C和C ++中以相同的方式引用结构,而在第二个版本中,它们在C中的引用与在C ++中的引用不同。
答案 1 :(得分:10)
首先,两个声明在C和C ++中都是合法的。但是,在C语言中,它们的语义略有不同。 (特别是,您稍后引用结构的方式会有所不同)。
要理解的关键概念是,在C中,结构存在于单独的命名空间中。
所有内置类型以及typedef都存在于“default”命名空间中。也就是说,当我键入int
时,编译器只检查这个“默认”命名空间。如果我在您的示例中键入“tagMyStruct”,编译器也只检查这一个命名空间。但是根据您使用的声明类型,该结构可能不存在于该命名空间中。
结构不同,并且存在于单独的命名空间中。所以如果我做出以下声明:
struct mystruct {};
我可以不简单地将其称为mystruct。相反,我必须指定我想要struct namespace中存在的mystruct:
void foo(struct mystruct bar); // Declare a function which takes a mystruct as its parameter
从长远来看,这有点冗长和尴尬。相反,您可以将其键入默认命名空间:
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);
所以你的第一个例子只是将这两个步骤合并在一起:声明一个struct,并将一个别名放入常规命名空间。当然,既然我们无论如何都要对它进行类型化,我们不需要“原始”名称,因此我们可以使结构匿名。在宣布之后
typedef struct { int i; double d; } tagMyStruct;
我们有一个没有名字的结构,它在默认名称空间中被“typedef”为“tagMyStruct”。
这就是C对待它的方式。两种类型的声明都是有效的,但是没有在“默认”命名空间中创建别名,所以每次引用类型时都必须使用struct关键字。
在C ++中,单独的struct命名空间不存在,因此它们的意思相同。 (但较短的版本是首选)。
编辑为了清楚起见,不,C没有名称空间。不是通常意义上的。 C只是将标识符放入两个预定义的命名空间之一。结构(和我记得的枚举)的名称放在一个中,所有其他标识符放在另一个中。从技术上讲,这些是命名空间,因为它们是单独的“容器”,其中放置了名称以避免冲突,但它们肯定不是C ++ / C#意义上的命名空间。
答案 2 :(得分:1)
这只是简写。
在第二个实例中,使用以下命令声明结构:
struct MyStruct a;
在第一个版本中,您可以使用:
tagMyStruct a;
答案 3 :(得分:0)
第二种变体也存在于C.
中只要您想为类型命名,就可以使用第一个变体,例如:
tagEnum myFunc(tagMyStruct * myArg);
答案 4 :(得分:0)
第一个可能在C ++中不方便,因为你无法在头文件中转发它。