提问



在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和其他标识符)。 [53] [54] [55]


如果你刚才说:


struct Foo { ... };
Foo x;


您会收到编译器错误,因为Foo仅在标记名称空间中定义。


你必须声明为:


struct Foo x;


任何时候你想引用Foo,你总是要把它称为struct Foo。这会很快烦人,所以你可以添加typedef:


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


现在struct Foo(在标记命名空间中)和普通Foo(在普通标识符命名空间中)都引用相同的东西,你可以自由地声明Foo类型的对象而不需要[[struct关键字。





结构:


typedef struct Foo { ... } Foo;


只是声明和typedef的缩写。





最后,


typedef struct { ... } Foo;


声明一个匿名结构并为其创建typedef。因此,使用此构造,它在标记名称空间中没有名称,只有typedef名称空间中的名称。这意味着它也不能向前声明。如果要进行前向声明,则需要在标记名称空间中为其命名。





在C ++中,所有struct/union/enum/class声明的行为就像隐含typedefed,只要名称不被隐藏另一个同名的声明。请参阅迈克尔伯尔的答案,了解详情。

其它参考1


在这篇DDJ文章中,Dan Saks解释了一个小区域,如果你没有输入你的结构(和类!),那么bug就会蔓延开来:[57]



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


typedef class string string;

  
  不幸的是,这并非完全如此
  准确。我希望就这么简单,
  但事实并非如此.C ++无法生成这样的东西
  结构,联合或枚举的typedef
  没有引入不兼容性
  用C.

  
  例如,假设一个C程序
  声明函数和结构
  命名状态:


int status(); struct status;

  
  同样,这可能是不好的做法,但是
  它是C.在这个程序中,状态(通过
  本身)指的是功能;结构
  status指的是类型。

  
  如果C ++确实自动生成
  标签的typedef,然后当你
  把这个程序编译为C ++ ,.
  编译器会生成:


typedef struct status status;

  
  不幸的是,这个类型名称会
  与函数名冲突,和
  该程序不会编译。那是
  为什么C ++不能简单地生成一个
  每个标签的typedef。

  
  在C ++中,标签就像typedef一样
  名称,但程序可以
  声明一个对象,函数或
  具有相同名称的枚举器
  与标签相同的范围。在那种情况下,
  对象,函数或枚举器名称
  隐藏标签名称。该计划可以
  仅通过使用来引用标签名称
  关键字class,struct,union或
  enum(视情况而定)在前面
  标签名。由...组成的类型名称
  其中一个关键字后跟一个
  tag是一个精心设计的类型说明符。
  例如,struct status和enum
  月份是精心设计的类型说明者。

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


int status(); struct status;

  
  编译为C ++时的行为相同。
  仅名称状态指的是
  功能。该程序可以参考
  只使用
  elaborated-type-specifier结构
  状态。

  
  那么这是如何让bug陷入困境的呢?
  进入程序?考虑一下该计划
  清单1.该程序定义了一个
  使用默认构造函数的类foo,
  和转换运算符
  将foo对象转换为char const *。
  表达[58]


p = foo();

  
  在main中应该构造一个foo对象
  并应用转换运算符。该
  后续输出声明


cout << p << '\n';

  
  应该显示类foo,但它
  没有。它显示功能foo。

  
  这个令人惊讶的结果是因为
  该程序包括头lib.h
  如清单2所示。此标头
  定义了一个名为foo的函数。该
  函数名称foo隐藏了类名
  foo,所以在main中引用foo
  是指函数,而不是类。
  main只能通过引用类
  使用精心设计的说明符,如
  在[59]


p = class foo();

  
  避免这种混乱的方法
  整个程序是添加的
  跟随类名称的typedef
  FOO:


typedef class foo foo;

  
  在课前或课后
  定义。这种typedef会导致a
  类型名称foo和。之间的冲突
  函数名称foo(来自
  库)将触发一个
  编译时错误。

  
  我知道没有人真正写作
  这些typedef当然是理所当然的。
  它需要很多纪律。以来
  错误的发生率如
  清单1中的一个可能很漂亮
  很小,你们很多人都不会发生冲突
  这个问题。但如果你的错误
  软件可能会造成人身伤害,
  那你应该写typedefs no
  重要的是错误的可能性。 [60]

  
  我无法想象为什么有人会这样
  想要隐藏一个类名
  功能或对象名称相同
  作为班级的范围。隐藏规则
  在C中是一个错误,他们应该
  没有扩展到课堂
  C ++。的确,你可以纠正
  错误,但它需要额外的
  编程学科和努力
  不应该是必要的。


其它参考2


一个更重要的区别:typedef s不能向前宣布。所以对于typedef选项,你必须#include包含typedef的文件,这意味着#include你的.h的所有内容都包含该文件是否直接需要它或不,等等。它肯定会影响您在大型项目上的构建时间。


如果没有typedef,在某些情况下,您只需在.h文件的顶部添加struct Foo;的前向声明,而#include只在您的#include中添加结构定义typedef 50]]文件。

其它参考3


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



   7.1.3 typedef说明符

  
  1 [[...]]

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

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



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


因此,typedef 始终用作另一种类型的占位符/同义词。

其它参考4


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


结构本身是一个匿名类型,因此你没有实际的名称来转发声明。


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


像这样的前瞻声明不会起作用:


struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types

其它参考5


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


// 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; };

其它参考6


Struct是创建数据类型。
typedef用于设置数据类型的昵称。

其它参考7


C ++没有区别,但是我相信它会允许你声明struct Foo的实例而不显式地做:


struct Foo bar;