结构体:一种数据类型。
结构体是一些值的集合,这些值被称为成员变量,结构的每个成员可以是不同类型的,也可以嵌套结构体。。
结构体的声明,结构体变量指针的创建
//结构体关键字 结构体便签
struct stu
{
int num;//成员变量
char name[20];//不用初始化
}s,*p;//结构体全局变量s,一个结构体指针p。
//结构体局部变量定义
int main()
{
struct stu a={1,"amy"};
struct stu*b=&a;
struct stu a={name="amy",num=1};//结构体乱序初始化
return0;
}
结构体本身无大小(int 本身也无大小),结构体变量才有大小。
结构体重命名:简化变量定义
typedef struct stu
{
int num;
char name[20];
}stu;//stu不是变量名
stu a={1,"amy"};
匿名结构体:省略标签,变量的创建只能在声明时创建
struct
{
int age;
char name[20];
}x;
访问结构体
变量名
// 变量名.成员变量名
printf("%d",stu.num);
//嵌套结构体
printf("%d",stu1.stu2.num);
地址
//变量名->成员变量名
printf("%d",stup->age);
//嵌套结构体
printf("%d",stu1p->stu2p->num);
结构体自引用:在结构体中引用结构体,如链表
struct Node
{int value =0;
struct Node* next
};
结构体内存对齐规则:把空间小的成员放在一起
第一个成员在偏移量为0处。
2.从第二个成员开始,每个成员在自身对齐数的整数倍处。
(对齐数=结构体成员大小和默认对齐数中的较小值,vs是8,Linux无默认是成员自己本身大小)
3.结构体大小是最大对齐数的整数倍。
修改默认对齐数:#program pack()
#program pack(4)//默认对齐数是4
#prgram pack()//恢复默认对齐数
#program pack(1)//默认对齐数为1,相当于无默认对齐数
计算结构体大小(以结构体s1为例)
求出各个变量的对齐数(规则2)。
按顺序把成员变量地址对齐到对齐数的整数倍处。
求最大的对齐数的最小整数倍。(4的3倍刚好装下s1)
struct s1
{ char c1;//1
int i;//4
char c2;//1
};
成员变量为数组int arr[n]时,相当于n个int型变量按顺序排列。
成员变量为结构体把自身变量大小和默认对齐数比较求出自身对齐数。
求出结构体偏移量来验证结构
宏offsetof计算成员偏移量
printf("%d\n",offsetof(struct s1,c1));//数据类型,成员变量名
//结构为0。
对齐能提高访问速度。
硬件只能访问某些特定地址的对齐数,数据,对齐时处理器只用要一次内存访问,非对齐要两。
如图,机器访问(红色,一次四个字节),int数据(绿色)要一次,char(蓝色),浪费空间(白色)
对齐只用访问一次,而非对齐要两次才能完整访问int数据。
结构体传参:传参要压栈,首选结构体地址
void fun1(struct s s1);
void fun2(struct s* ps);
位段:单位为bit,共用结构体关键字的数据类型
struct A{
int _a:2;//只占两个比特位
int _c:5;
int _c:5;
}
成员必须是整型家族int,unsigned int 或char (一般同类型)
位段成员名后边有一个冒号和数字
位段空间开辟:以(int,unsigned)4个字节或(char)1个字节开辟空间
int:开辟32个比特位(32个字节),能装下_a,_b,_c,不够再开辟4个字节。
char:先开辟8个比特位(1个字节),不够再开辟1个字节。
位段数据的存储以及位段的大小(以下举例是在vs环境下)
struct stu {
char a : 3;
char b : 6;
char c : 3;
}A;
int main()
{
A.a = 9;
A.b = 3;
A.c = 4;
}
a:1001(9)大于3个比特位,截断1001->001 第一个字节中(*大端存放)
b:剩下的比特位不足以放6个比特位,再开辟1个字节空间。不用截断再放入
c:一样。
跨平台问题
位段中int是有符号还是无符号不确定
位段int的大小是不确定的
位段使用一个字节的方式不确定(小端还是大端)
当一个结构包含两个位段,第二个位段成员比较大,无法容纳第一个位段剩余的位时时,是否舍弃位还是利用是不确定的。(vs中舍弃)