是一个结构{…}; 一个类型或一个未命名的变量?

在文件范围,以下是类型声明还是未命名变量?

struct student_s { char* name; int age; double height; struct student_s* next; }; 

如果是类型定义,那么有什么区别:

 typedef struct student_s { char* name; int age; double height; struct student_s* next; }; 

(背景:请参阅我的答案将变量从全局更改为本地 – C ,我相信第一个引入了一个未命名的变量,然后由编译器对其进行优化。)

注意 :该问题已被标记为可能重复的结构成员标识符放在什么范围内? 但我相信我不是在询问有关成员范围的问题,而是询问有关声明实际创造的内容。 然而。 回答C ++中’struct’和’typedef struct’的区别? 解释我的问题。

根据C标准,结构声明的forms如

 struct student_s { char* name; int age; double height; struct student_s* next; }; 

是一种类型的声明。 引用C11 ,章节§6.7.2.1

struct-or-union-specifier中struct-declaration-list的存在在转换单元中声明了一个新类型。 struct-declaration-list是结构或联合成员的一系列声明。 […]

C标准不要求为该类型创建变量 (命名或未命名)。

在你的第二个片段中,你实际上( 尝试 )将typedef 。 但是,如果您将代码段更改为

 typedef struct { //.....members } student_s ; 

你将创建一个类型 student_stypedef到一个未命名的结构类型),你可以在以后使用它。

FWIW,我们从不谈论过这里创建的变量。 这都是关于类型的

第一个声明声明了一个类型。 在声明之后,类型struct student_s是已知的,您可以声明该类型的变量或指向它的指针:

 struct student_s student1; struct student_s *pStudent; 

即使编译,第二个声明也很奇怪。 常见的用法是:

 typedef struct { char* name; int age; double height; struct student_s* next; } studend_t; 

它将别名student_t声明为匿名结构。 然后可以直接使用它:

 student_t student1; student_t *pStudent; 

但第二个例子是编译(即使有警告),并且是第一个!

它真正做的是为struct student_s声明一个void别名。 typedef被忽略并产生一个警告: typedef需要一个名称 ,但作为一个副作用,结构被声明,就像在第一个例子中一样。

因此,实际问题的真正答案是除了警告之外没有差别

两者都是类型定义。 第二个是一个不完整的。 它不提供名称作为typedef的参数。 更好的是使用

 typedef struct student_s { char* name; int age; double height; struct student_s* next; } student; 

关于合法性

 typedef struct student_s { char* name; int age; double height; struct student_s* next; }; 

我已经问过这个问题, `typedef struct foo {int bar};`的合法性

它是一种类型,你不能拥有一个结构的匿名实例。 为了进行比较,这将声明类型struct_type 该类型的实例struct_instance

 struct struct_type { /* blah */ } struct_instance; 

如果你想要隔离地声明另一个实例(来自类型decl)你将使用

 struct struct_type another_instance; 

使用typedef – 如果正确完成,与您的示例不同 – 只允许您为类型指定另一个名称,该名称不需要struct关键字来声明实例:

 typedef struct_type MyStruct; MyStruct yet_another_instance; 

或者等价的

 typedef struct struct_type { /* blah */ } MyStruct; 

省略名称( struct_type )会为您提供一个匿名结构类型,该结构类型只能通过其typedef名称引用。


注1

由于原始struct包含指向其自身类型的next指针,因此该类型必须在声明成员的位置具有名称 。 因此,您不能使用自键型指针声明匿名结构。 如果您为匿名结构类型指定了一个名为typedef的名称,那么该名称在成员声明之后才会存在,因此不能在那里使用。

 typedef struct /*S*/ { struct S *next; /* T doesn't exist yet, so without S, you can't declare this */ } T; 

笔记2

可以将匿名联合的匿名实例声明为成员:

 struct S { union { int i; unsigned u; }; }; struct S s; si = -1; printf("%x\n", su); 

但这是一个非常特殊的情况。 我从主要论点中听取了关于这一点的评论,以防它误导。

不同之处在于,对于第一个示例,您必须声明一个如下所示的新变量: struct student_s variable; 但是,对于第二个例子,你可以简单地做student_s variable;

 struct A { ... } 

struct命名空间中创建struct ‘可见(它与C ++命名空间没有任何共同之处)。 因此,要访问struct您必须使用struct关键字;

 struct A a; 

使用typedef结构定义时

 typedef struct A { ... } B; 

变得可见并绑定到B,您可以轻松地创建类似B的公共变量的struct

 B a; 

如果我错了,请纠正我。