结构体是一些值的集合,称这些值为结构体成员,结构体成员可以是不同的类型,比如 int、float、char、double、指针等。
struct student{
int num;
char name[10];
char f;
int age;
}stu;
比如这是包含一个学生的结构体,包含学生信息有学号num、姓名name、性别f、年龄age
计算结构体的大小就需要知道结构体在内存中是如何存储的,在这之前需要了解两个概念
(1)偏移量,结构体中成员的偏移量=上一个成员的的偏移量+上一个成员的大小。 (以上面的学生结构体为例:)
偏移量(name)=偏移量(int)+sizeof(int) ;
偏移量(age)=偏移量(f)+sizeof(f);
这里还要注意,成员的偏移量必须是成员大小的整数倍(0是任何数的整数倍),比如上面的age为int类型,则偏移量(int)是4的整数倍。
(2)内存对齐,结构体的大小必须是每一位成员大小的整数倍
以上面的学生结构体为例,计算大小
偏移量(int)=0+0=0
偏移量(name)=0+4=4
偏移量(f)=4+10=14
偏移量(age)=14+1=15 //15不是int成员大小的倍数 所以偏移量(int)=15+1=16
结构体大小=偏移量(age)+sizeof(age)=16+4=20
默认以成员中最大的来对齐,上面结构体中最大的为int,所以假设一行存放4字节。不够四字节自动补齐,虽然有char name[10],但我们把它当成10个1字节来看。
还有这种情况,结构体套结构体
比如:
struct s{
char ch;
struct
{
char c;
int a;
}x;
};
这里把嵌套的结构体展开即可,但要注意,展开后的结构体中第一个成员的偏移量应该是它所属结构体中最大成员的整数倍(这个例子中体现为偏移量(c)是sizeof(a)的整数倍)
偏移量(ch)=0
偏移量(c)=0+1=1 这里嵌套结构体中最大为int,所以偏移量(c)应该为4的整数倍 所以偏移量(c)=1+3=4
偏移量(a)=4+1=5 偏移量为成员大小整数倍,所以偏移量(a)=5+3=8
结构体大小=8+4=12 12为所有成员大小的整数倍
struct s{
int a;
char c;
};
偏移量(a)=0
偏移量(c)=0+4=4
结构体大小=4+1=5 因为5不是int大小的(4)的整数倍(结构体的大小必须是每一位成员大小的整数倍)
所以结构体大小为 5+3=8
这里介绍一种指定结构体对齐方式 #pragam pack(vaule).
#pragam pack(vaule)
#pragma pack(4)
struct s{
char ch;
double m;
int n;
};
偏移量(ch)=0 0是4的倍数
偏移量(m)=0+1=1 不是4的倍数,因此偏移量(m)=1+3=4
偏移量(n)=4+8=12
结构体大小=12+4=16
可以看出,每个成员的偏移量是指定对齐值的倍数。
若指定的大小>最大成员的大小 则以自身对齐为准
指定的大小<最大成员的大小 则以指定为准
宏 offsetof(type,number) 作用是计算结构体成员的偏移量,头文件为《stddef.h》
位段
在结构体中允许以“位”为单位来指定其成员所占内存长度。利用位段能够用较少的位数存储数据,位段存储于一个或多个整形变量中,也就是说位段的大小最位4的整数倍,最小为4.
比如,一个float型,为4字节,一共4*8=32位
struct test
{
unsigned int tail : 23;
unsigned int exp : 8;
unsigned int sign : 1;
};
成员分别为尾数位,指数位,标志位,这个位段大小为4字节
unsigned int : 0 的作用是让下一个变量从一个新的整型开始
struct test
{
unsigned int tail : 23;
unsigned int exp : 8;
unsigned int : 0
unsigned int sign : 1;
};
现在这个位段大小为8字节,首先23+8=31,遇到占位,将这个整型补齐为32,然后将sign存储在下一个整型中
联合
联合中所有成员使用的是相同的内存位置,声明如下:
union{
float f;
int i;
char s[5];
};
比如这里f与i存储在内存中的相同位置,如成员f被使用,内存中这个位置的值被当做浮点型使用,当i被使用时,这个位置的值被当做整型使用。
联合体的大小以成员中最大的为准,并且对齐方式要适合所有成员。
上面这个联合体中float占4字节,int占4字节,字符数组为5字节,所以最大为5,但5不是4的整数倍,所以最终联合体的大小为8。