Difference between 'struct' and 'typedef struct' in C++?
在C++中,有没有不同之处:
1 | struct Foo { ... }; |
和
1 | typedef struct { ... } Foo; |
在C++中,只有细微的差别。这是C的延期,在这方面有区别。
C语言标准(C89第3.1.2.3条、C99第6.2.3条和C11第6.2.3条)规定了不同类别标识符的单独名称空间,包括标签标识符(用于
如果你只是说:
1 2 | struct Foo { ... }; Foo x; |
您会得到一个编译器错误,因为
你必须声明它是:
1 | struct Foo x; |
每当你想提到一个
1 2 | struct Foo { ... }; typedef struct Foo Foo; |
现在,
构造:
1 | typedef struct Foo { ... } Foo; |
只是声明和
最后,
1 | typedef struct { ... } Foo; |
声明一个匿名结构并为它创建一个
在C++中,所有的EDCOX1,0,EDCOX1,1,E/OCX1,2,EDCX1,17个声明都像隐式EDOCX1,3’ED一样,只要名字不被另一个相同名称的声明所隐藏。详情请参阅迈克尔?伯尔的回答。
在这篇DDJ文章中,DanSaks解释了一个小的领域,如果你不定义你的结构(和类),bug可以在这个领域中蔓延。:
If you want, you can imagine that C++
generates a typedef for every tag
name, such as
1 typedef class string string;Unfortunately, this is not entirely
accurate. I wish it were that simple,
but it's not. C++ can't generate such
typedefs for structs, unions, or enums
without introducing incompatibilities
with C.For example, suppose a C program
declares both a function and a struct
named status:
1 int status(); struct status;Again, this may be bad practice, but
it is C. In this program, status (by
itself) refers to the function; struct
status refers to the type.If C++ did automatically generate
typedefs for tags, then when you
compiled this program as C++, the
compiler would generate:
1 typedef struct status status;Unfortunately, this type name would
conflict with the function name, and
the program would not compile. That's
why C++ can't simply generate a
typedef for each tag.In C++, tags act just like typedef
names, except that a program can
declare an object, function, or
enumerator with the same name and the
same scope as a tag. In that case, the
object, function, or enumerator name
hides the tag name. The program can
refer to the tag name only by using
the keyword class, struct, union, or
enum (as appropriate) in front of the
tag name. A type name consisting of
one of these keywords followed by a
tag is an elaborated-type-specifier.
For instance, struct status and enum
month are elaborated-type-specifiers.Thus, a C program that contains both:
1 int status(); struct status;behaves the same when compiled as C++.
The name status alone refers to the
function. The program can refer to the
type only by using the
elaborated-type-specifier struct
status.So how does this allow bugs to creep
into programs? Consider the program in
Listing 1. This program defines a
class foo with a default constructor,
and a conversion operator that
converts a foo object to char const *.
The expression
1 p = foo();in main should construct a foo object
and apply the conversion operator. The
subsequent output statement
1
2 cout << p << '
';should display class foo, but it
doesn't. It displays function foo.This surprising result occurs because
the program includes header lib.h
shown in Listing 2. This header
defines a function also named foo. The
function name foo hides the class name
foo, so the reference to foo in main
refers to the function, not the class.
main can refer to the class only by
using an elaborated-type-specifier, as
in
1 p = class foo();The way to avoid such confusion
throughout the program is to add the
following typedef for the class name
foo:
1 typedef class foo foo;immediately before or after the class
definition. This typedef causes a
conflict between the type name foo and
the function name foo (from the
library) that will trigger a
compile-time error.I know of no one who actually writes
these typedefs as a matter of course.
It requires a lot of discipline. Since
the incidence of errors such as the
one in Listing 1 is probably pretty
small, you many never run afoul of
this problem. But if an error in your
software might cause bodily injury,
then you should write the typedefs no
matter how unlikely the error.I can't imagine why anyone would ever
want to hide a class name with a
function or object name in the same
scope as the class. The hiding rules
in C were a mistake, and they should
not have been extended to classes in
C++. Indeed, you can correct the
mistake, but it requires extra
programming discipline and effort that
should not be necessary.
还有一个重要区别:
如果没有
有区别,但很微妙。这样看:
7.1.3 The typedef specifier
1 [...]
A name declared with the typedef specifier becomes a typedef-name. Within the scope of its declaration, a
typedef-name is syntactically equivalent to a keyword and names the type associated with the identifier in
the way described in Clause 8. A typedef-name is thus a synonym for another type. A typedef-name does not introduce a new type the way a class declaration (9.1) or enum declaration does.8 If the typedef declaration defines an unnamed class (or enum), the first typedef-name declared by the declaration
to be that class type (or enum type) is used to denote the class type (or enum type) for linkage
purposes only (3.5). [ Example:
1 | typedef struct { } *ps, S; // S is the class name for linkage purposes |
因此,typedef总是用作另一类型的占位符/同义词。
不能对typedef结构使用forward声明。
结构本身是匿名类型,因此您没有要转发声明的实际名称。
1 2 3 4 | typedef struct{ int one; int two; }myStruct; |
这样的前瞻性声明是行不通的:
1 2 3 4 5 | struct myStruct; //forward declaration fails void blah(myStruct* pStruct); //error C2371: 'myStruct' : redefinition; different basic types |
结构是创建数据类型。typedef用于设置数据类型的昵称。
C++中的"TyButfStutt"和"Stult"之间的一个重要区别是,"TyPulfStruts"中的内联成员初始化将不起作用。
1 2 3 4 5 | // 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; }; |
C++中没有区别,但是我相信在C中,它将允许您在没有显式地执行的情况下声明结构FUO的实例:
1 | struct Foo bar; |