以下是文件范围,类型声明还是未命名的变量?
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;
};
(背景:请参阅我在Changing a variable from global to local - C的回答,我相信第一个引入了一个未命名的变量,然后由编译器进行优化。)
注意:该问题已被标记为In what scope is a struct member identifier put?的可能副本,但我相信我不会询问有关成员范围的问题,而是关于声明实际创建的内容。然而。 Difference between 'struct' and 'typedef struct' in C++?的答案确实解释了我的问题。
答案 0 :(得分:6)
根据C
标准,形式为
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_s
(typedef
到未命名的结构类型),稍后您可以使用它。
FWIW,我们从未谈论这里创建的变量,无论如何。这完全是关于类型。
答案 1 :(得分:3)
第一个声明声明了一个类型。在声明之后,类型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需要一个名称,但作为一个副作用,结构被声明,就像在第一个例子中一样。
所以除了警告之外,实际问题的真正答案是没有差异。
答案 2 :(得分:2)
两者都是类型定义。第二个是一个不完整的。它没有提供名称作为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;
};
我已经问过这个单独的问题,Legality of `typedef struct foo {int bar};`
答案 3 :(得分:1)
它是一种类型,你不能拥有一个结构的匿名实例。为了进行比较,这会声明类型为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"名称来引用。
由于您的原始结构包含指向其自身类型的next
指针,因此该类型必须在声明该成员时具有名称。所以,不能使用自键型指针声明一个匿名结构。如果您为匿名结构类型指定了typedef
的名称,则该名称在成员声明之后才会存在,因此无法在此处使用。
typedef struct /*S*/ {
struct S *next; /* T doesn't exist yet, so without S, you can't declare this */
} T;
你可以声明一个匿名联盟的匿名实例,作为成员:
struct S {
union {
int i;
unsigned u;
};
};
struct S s;
s.i = -1;
printf("%x\n", s.u);
但这是一个非常特殊的案例。我把这个说法从主要论点中删除了,以防它误导。
答案 4 :(得分:0)
不同之处在于,对于第一个示例,您必须声明一个新变量:struct student_s variable;
,但是对于第二个示例,您可以只执行student_s variable;
。
答案 5 :(得分:0)
struct A { ... }
创建struct
' A'在struct
命名空间中可见(与C ++命名空间没有任何共同之处)。因此,要访问struct
,您必须使用struct
关键字;
struct A a;
使用typedef struct
定义时typedef struct A { ... } B;
变得可见并绑定到B,您可以轻松创建类似B的公共变量struct
B a;
如果我错了,请纠正我。