Struct declaration
Struct declaration
结构是一种由一系列成员组成的类型,其存储按有序顺序进行分配(与union相反,这是一种由存储重叠的成员序列组成的类型)。
union
除了使用的关键字之外,结构的类型说明符与 类型说明符相同:
句法
结构名称(可选){结构声明列表} | (1) | |
---|---|---|
结构名称 | (2) | |
1)结构定义:引入新的类型结构名称并定义它的含义
2)如果在struct
名称上使用它自己的行;
,则声明
但不定义该结构name
(请参见下面的前向声明
)。在其他上下文中,命名先前声明
的结构。
name | - | 正在定义的结构的名称 |
---|---|---|
结构声明列表 | - | 任何数量的变量声明,位域声明和静态断言声明。不完整类型的成员和函数类型的成员是不允许的(除了下面描述的灵活数组成员) |
说明
在一个结构对象中,其元素的地址(以及位字段分配单元的地址)按照成员定义的顺序增加。指向结构的指针可以转换为指向其第一个成员的指针(或者,如果该成员是位域,则指向其分配单元)。同样,可以将指向结构第一个成员的指针转换为指向封闭结构的指针。在结构的任何两个成员之间或者在最后一个成员之后,可能存在未命名的填充,但不在第一个成员之前。结构的大小至少与其成员大小的总和一样大。
如果一个结构至少定义了一个指定的成员,那么它允许额外地声明它的最后一个成员为不完整的数组类型。当访问灵活数组成员的元素时(在使用运算符的表达式中,或者使用灵活数组成员的名称作为右手边操作数),那么结构的行为就好像数组成员具有最长的大小适合为该对象分配的内存。如果没有分配额外的存储空间,则它的行为就像一个具有1个元素的数组,除非该行为是未定义的(如果访问该元素或产生了经过该元素的指针)。初始化,sizeof和赋值运算符忽略了灵活的数组成员。具有灵活数组成员的结构(或其最后一个成员是具有灵活数组成员的结构的联合结构)不能以数组元素或其他结构成员的形式出现。struct s {int n; double d []; }; // sd是一个灵活的数组成员struct s t1 = {0}; // OK,d就好像是double d1,但UB访问struct s t2 = {1,{4.2}}; //错误:初始化忽略灵活数组//如果sizeof(double)== 8 struct s * s1 = malloc(sizeof(struct s)+ 64); //好像d是双d8 struct s * s2 = malloc(sizeof(struct s)+ 46); //好像d是double d5 s1 = malloc(sizeof(struct s)+ 10); //现在好像d是double d1 s2 = malloc(sizeof(struct s)+ 6); //相同,但UB访问double * dp =&(s1-> d0); // OK * dp = 42; // OK dp =&(s2-> d0); // OK * dp = 42; //未定义行为* s1 = * s2; //只复制sn,而不是sd的任何元素//除了在sizeof(struct s)中捕获的元素外, | (自C99以来) |
---|
类似于联合,一个结构的未命名成员的类型是一个没有名字的结构被称为匿名结构。匿名结构的每个成员都被认为是封闭结构或联合的成员。如果封闭的结构或联合也是匿名的,则这将递归应用。struct v {union {//匿名联合结构{int i,j; }; //匿名结构struct {long k,l; } w; }; int m; } v1; v1.i = 2; //有效v1.k = 3; //无效:内部结构不是匿名的v1.wk = 5; // valid与union类似,如果struct没有任何指定成员(包括通过匿名嵌套结构或联合获得的成员)定义,则程序的行为是未定义的。 | (自C11以来) |
---|
前向声明
以下表格的声明。
结构名称; | | |
---|
隐藏标签名称空间中名称名称的任何先前声明的含义,并将名称声明为当前作用域中的新结构名称,稍后将对其进行定义。在定义出现之前,此结构名称的类型不完整。
这允许相互引用的结构:
struct y;
struct x { struct y *p; /* ... */ };
struct y { struct x *q; /* ... */ };
请注意,只需在另一个声明中使用结构标签即可引入新的结构名称,但如果在标签名称空间中存在以前声明的具有相同名称的结构,则该标签将引用该名称。
struct s* p = NULL; // tag naming an unknown struct declares it
struct s { int a; }; // definition for the struct pointed to by p
void g(void)
{
struct s; // forward declaration of a new, local struct s
// this hides global struct s until the end of this block
struct s *p; // pointer to local struct s
// without the forward declaration above,
// this would point at the file-scope s
struct s { char* p; }; // definitions of the local struct s
}
关键词
struct
.
注释
有关结构初始化程序的规则,请参阅结构初始化。
因为不完整类型的成员是不允许的,并且结构类型直到定义结束才会完成,所以结构体不能拥有自己类型的成员。允许指向它自己的类型的指针,并且通常用于实现链接列表或树中的节点。
因为结构声明不会建立范围,所以struct-declaration-list中的声明引入的嵌套类型,枚举和枚举器在定义了结构的周围范围内是可见的。
例
#include <stddef.h>
#include <stdio.h>
int main(void)
{
struct car { char *make; char *model; int year; }; // declares the struct type
// declares and initializes an object of a previously-declared struct type
struct car c = {.year=1923, .make="Nash", .model="48 Sports Touring Car"};
printf("car: %d %s %s\n", c.year, c.make, c.model
// declares a struct type, an object of that type, and a pointer to it
struct spaceship { char *make; char *model; char *year; }
ship = {"Incom Corporation", "T-65 X-wing starfighter", "128 ABY"},
*pship = &ship;
printf("spaceship: %s %s %s\n", ship.year, ship.make, ship.model
// addresses increase in order of definition
// padding may be inserted
struct A { char a; double b; char c;};
printf("offset of char a = %zu\noffset of double b = %zu\noffset of char c = %zu\n"
"sizeof(struct A)=%zu\n", offsetof(struct A, a), offsetof(struct A, b),
offsetof(struct A, c), sizeof(struct A)
struct B { char a; char b; double c;};
printf("offset of char a = %zu\noffset of char b = %zu\noffset of double c = %zu\n"
"sizeof(struct B)=%zu\n", offsetof(struct B, a), offsetof(struct B, b),
offsetof(struct B, c), sizeof(struct B)
// A pointer to a struct can be cast to a pointer to its first member and vice versa
char* pmake = (char*)&ship;
pship = (struct spaceship *)pmake;
}
可能的输出:
car: 1923 Nash 48 Sports Touring Car
spaceship: 128 ABY Incom Corporation T-65 X-wing starfighter
offset of char a = 0
offset of double b = 8
offset of char c = 16
sizeof(struct A)=24
offset of char a = 0
offset of char b = 1
offset of double c = 8
sizeof(struct B)=16
参考
- C11标准(ISO / IEC 9899:2011):