C ++中“struct”和“typedef struct”的区别?

在C ++中,是否有任何区别:

struct Foo { ... }; 

 typedef struct { ... } Foo; 

在C ++中,只有一个细微的差别。 这是来自C的一个延续,在这里它有所作为。

C语言标准( C89§3.1.2.3 , C99§6.2.3和C11§6.2.3 )为不同类别的标识符(包括标签标识符struct / union / enum )和普通标识符typedef和其他标识符)。

如果你只是说:

 struct Foo { ... }; Foo x; 

你会得到一个编译器错误,因为Foo只在标签名称空间中定义。

您必须将其声明为:

 struct Foo x; 

任何时候你想引用一个Foo ,你总是要把它叫做一个struct Foo 。 这很快恼人,所以你可以添加一个typedef

 struct Foo { ... }; typedef struct Foo Foo; 

现在, struct Foo (在标记名称空间中)和Foo (在普通标识符名称空间中)都指向相同的事物,并且可以在不使用struct关键字的情况下自由声明Footypes的对象。


构造:

 typedef struct Foo { ... } Foo; 

只是声明和typedef的缩写。


最后,

 typedef struct { ... } Foo; 

声明一个匿名结构并为其创build一个typedef 。 因此,使用这个构造,它在标签名称空间中没有名称,在typedef名称空间中只有一个名称。 这意味着它也不能被宣布。 如果你想做一个前向声明,你必须在标签名称空间中给它一个名字


在C ++中,只要名称不被具有相同名称的另一个声明隐藏,所有的struct / union / enum / class声明都会像隐式的typedef一样工作。 详见Michael Burr的回答 。

在这篇DDJ文章中 ,Dan Saks解释了一个小的区域,如果你没有input你的结构(和类!

如果你愿意的话,你可以想象C ++为每个标签名称生成一个typedef,例如

 typedef class string string; 

不幸的是,这并不完全准确。 我希望这很简单,但事实并非如此。 C ++不能为结构体,联合体或枚举生成这样的typedef,而不会引入与C的不兼容性。

例如,假设一个C程序声明了一个名为status的函数和一个结构体:

 int status(); struct status; 

再次,这可能是不好的做法,但它是C.在这个程序中,状态(本身)是指function; 结构状态指的是types。

如果C ++自动为标签生成typedef,那么当你编译这个程序为C ++时,编译器会生成:

 typedef struct status status; 

不幸的是,这个types名称与函数名称冲突,程序不能编译。 这就是为什么C ++不能简单地为每个标签生成一个typedef的原因。

在C ++中,标签的作用就像typedef名称一样,只不过程序可以声明与标签具有相同名称和范围的对象,函数或枚举器。 在这种情况下,对象,函数或枚举器名称将隐藏标记名称。 程序只能通过在标签名称前使用关键字class,struct,union或enum(如适用)来引用标签名称。 由这些关键字之后跟一个标签组成的types名称是一个详细说明types说明符。 例如,struct status和enum month是详细说明types说明符。

因此,一个包含以下两者的C程序:

 int status(); struct status; 

在编译为C ++时performance相同。 单独的名称状态是指该function。 程序只能通过使用elaborated-type-specifier结构状态来引用types。

那么这是如何让bug进入程序的呢? 考虑清单1中的程序。 这个程序定义了一个具有默认构造函数的类foo,以及一个将foo对象转换为char const *的转换运算符。 expression方式

 p = foo(); 

主要构造一个foo对象并应用转换操作符。 随后的输出语句

 cout << p << '\n'; 

应该显示类foo,但它不。 它显示函数foo。

出现这个令人惊讶的结果是因为程序包含清单2所示的头文件lib.h。 这个头文件定义了一个名为foo的函数。 函数名foo隐藏类名foo,所以在main中对foo的引用是指函数,而不是类。 主要只能通过使用详细types说明符来引用类

 p = class foo(); 

在整个程序中避免这种混淆的方法是为类名foo添加以下typedef:

 typedef class foo foo; 

紧接在类定义之前或之后。 这个typedef会导致types名称foo和函数名foo(来自库)之间的冲突,这会触发编译时错误。

我知道没有人真的写这些typedef当然。 这需要很多纪律。 由于清单1中的错误发生率可能相当小,所以很多人从来不会遇到这个问题。 但是,如果软件中的错误可能会导致人身伤害,那么无论出现错误的程度如何,都应该写入typedef。

我无法想象为什么有人会想要隐藏一个类名与一个函数或对象名称在同一范围内的类。 C中的隐藏规则是一个错误,它们不应该被扩展到C ++中的类。 事实上,你可以纠正这个错误,但是这需要额外的编程纪律和努力,而这是不必要的。

一个更重要的区别是: typedef不能被声明。 因此,对于typedef选项,您必须#include包含包含typedef的文件,这意味着#include您的.h文件包含该文件,无论它是否直接需要它,依此类推。 它肯定会影响您在大型项目上的构build时间。

没有typedef ,在某些情况下,你可以添加一个struct Foo;的前向声明struct Foo;.h文件的顶部,并且只包含.h文件中的结构定义。

有一个区别,但微妙。 这样看: struct Foo引入了一个新的types。 第二个为未命名的structtypes创build一个名为Foo的别名(而不是新types)。

7.1.3 typedef说明符

1 […]

使用typedef说明符声明的名称将成为typedef名称。 在其声明的范围内,typedef-name在语法上等同于一个关键字,并以第8章描述的方式命名与该标识符关联的types。typedef-name因此是另一个types的同义词。 typedef名称不会像类声明(9.1)或枚举声明那样引入新types

8如果typedef声明定义了一个未命名的类(或枚举),则声明声明的第一个typedef-name是类types(或枚举types),用于表示仅用于链接目的的类types(或枚举types) 3.5)。 [例如:

 typedef struct { } *ps, S; // S is the class name for linkage purposes 

所以,typedef 总是被用作另一个types的占位符/同义词。

您不能使用typedef结构的前向声明。

结构本身是一个匿名types,所以你没有一个实际的名字来转发declare。

 typedef struct{ int one; int two; }myStruct; 

像这样的前进宣言不会奏效:

 struct myStruct; //forward declaration fails void blah(myStruct* pStruct); //error C2371: 'myStruct' : redefinition; different basic types 

C ++中的'typedef struct'和'struct'之间的一个重要区别是'typedef structs'中的内联成员初始化不起作用。

 // the 'x' in this struct will NOT be initialised to zero typedef struct { int x = 0; } Foo; // the 'x' in this struct WILL be initialised to zero struct Foo { int x = 0; }; 

Struct是创build一个数据types。 typedef是为数据types设置一个昵称。

在C ++中没有什么区别,但我相信在C中它可以让你声明结构Foo的实例而不显式地执行:

 struct Foo bar;