在c++中,有什么区别:

struct Foo { ... };

and:

typedef struct { ... } Foo;

当前回答

在c++中,只有细微的区别。它是C语言的延续,在C语言中是有区别的。

C语言标准(C89§3.1.2.3,C99§6.2.3和C11§6.2.3)要求对不同类别的标识符使用单独的名称空间,包括标签标识符(用于struct/union/enum)和普通标识符(用于类型定义和其他标识符)。

如果你说:

struct Foo { ... };
Foo x;

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

你必须声明它为:

struct Foo x;

任何时候你想引用一个Foo,你总是必须称它为结构体Foo。这很快就会让人讨厌,所以你可以添加一个类型定义:

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

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


构造:

typedef struct Foo { ... } Foo;

只是声明和类型定义的缩写。


最后,

typedef struct { ... } Foo;

声明一个匿名结构并为其创建一个类型定义。因此,使用这个构造,它在标记名称空间中没有名称,而在typedef名称空间中只有名称。这意味着它也不能前向声明。如果希望进行前向声明,则必须在标记名称空间中为其指定一个名称。


在c++中,所有struct/union/enum/class声明都是隐式类型定义的,只要该名称没有被另一个同名声明所隐藏。详见Michael Burr的回答。

其他回答

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

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

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

像这样的前向声明是行不通的:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

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

在这篇DDJ文章中,Dan Saks解释了一个小领域,如果你没有对你的结构(和类!)进行类型定义,bug就会蔓延:

If you want, you can imagine that C++ generates a typedef for every tag name, such as 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: 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: 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: 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 p = foo(); in main should construct a foo object and apply the conversion operator. The subsequent output statement cout << p << '\n'; 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 p = class foo(); The way to avoid such confusion throughout the program is to add the following typedef for the class name foo: 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.

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

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

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

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:

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

因此,类型定义总是用作另一种类型的占位符/同义词。

在c++中,只有细微的区别。它是C语言的延续,在C语言中是有区别的。

C语言标准(C89§3.1.2.3,C99§6.2.3和C11§6.2.3)要求对不同类别的标识符使用单独的名称空间,包括标签标识符(用于struct/union/enum)和普通标识符(用于类型定义和其他标识符)。

如果你说:

struct Foo { ... };
Foo x;

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

你必须声明它为:

struct Foo x;

任何时候你想引用一个Foo,你总是必须称它为结构体Foo。这很快就会让人讨厌,所以你可以添加一个类型定义:

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

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


构造:

typedef struct Foo { ... } Foo;

只是声明和类型定义的缩写。


最后,

typedef struct { ... } Foo;

声明一个匿名结构并为其创建一个类型定义。因此,使用这个构造,它在标记名称空间中没有名称,而在typedef名称空间中只有名称。这意味着它也不能前向声明。如果希望进行前向声明,则必须在标记名称空间中为其指定一个名称。


在c++中,所有struct/union/enum/class声明都是隐式类型定义的,只要该名称没有被另一个同名声明所隐藏。详见Michael Burr的回答。