C ++中'struct'和'typedef struct'之间的区别?

时间:2009-03-04 20:41:12

标签: c++ struct typedef

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

struct Foo { ... };

typedef struct { ... } Foo;

8 个答案:

答案 0 :(得分:1107)

在C ++中,只有一个微妙的区别。这是C的延续,它有所作为。

C语言标准(C89 §3.1.2.3C99 §6.2.3C11 §6.2.3)要求为不同类别的标识符分别设置名称空间,包括标记标识符(用于{{ 1}} / 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类型的对象没有Foo关键字。


构造:

struct

只是声明的缩写,typedef struct Foo { ... } Foo;


最后,

typedef

声明一个匿名结构并为其创建typedef struct { ... } Foo; 。因此,使用此构造,它在标记名称空间中没有名称,只有typedef名称空间中的名称。这意味着它也无法向前宣布。 如果要进行前向声明,则必须在标记名称空间中为其命名。


在C ++中,所有typedef / struct / union / enum声明都表现得像隐式class',只要名称是没有被另一个具有相同名称的声明隐藏。有关详细信息,请参阅Michael Burr's answer

答案 1 :(得分:216)

this DDJ article中,Dan Saks解释了一个小区域,如果你没有输入你的结构(和类!),那么bug就会蔓延开来:

  

如果你愿意,你可以想象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陷入困境的呢?   进入程序?考虑一下该计划   Listing 1。该程序定义了一个   使用默认构造函数的类foo,   和转换操作符   将foo对象转换为char const *。   表达式

p = foo();
     main中的

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

cout << p << '\n';
     

应该显示类foo,但它   没有。它显示了函数foo。

     

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

p = class foo();
     

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

typedef class foo foo;
     

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

     

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

     

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

答案 2 :(得分:62)

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

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

答案 3 :(得分:31)

有区别,但很微妙。这样看: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 :(得分:10)

您不能将前向声明与typedef结构一起使用。

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

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

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

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

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

答案 5 :(得分:1)

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

答案 6 :(得分:0)

&#39; typedef结构之间的重要区别&#39;和一个&#39;结构&#39;在C ++中,&#39; typedef结构中的内联成员初始化&#39;不行。

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

答案 7 :(得分:-3)

C ++没有区别,但是我相信它会允许你在不明确地做声明的情况下声明struct Foo的实例:

struct Foo bar;