一、结构体
1、结构体的声明
使用关键字struct 定义:
struct tag
{
number_list//成员列表
}variable _list;//分号不能丢
在声明的时候,可以不完全声明,(可以省略 tag 或者variable_list)
2、结构体自引用
struct Node
{
int date;
struct Node*next;
}
3、结构体变量的定义和初始化
(1)定义结构体变量
struct Point
{
int x;
int y;
}p1;//声明类型的同时定义变量p1;
struct Point p2;//定义结构体变量p2;
struct Point p3={x,y};.//声明并初始化
4、结构体内存对齐
(1) 当我们要计算结构体的大小时,为什么要按照结构体内存对齐规则?
举个例子:
struct P
{
char i;
int b;
}x;
要访问结构体变量的成员时,需要通过(.),比如x.i ,x.b;
如果时CPU访问内存中的x.i ,x.b时,由于硬件平台的限制,会增加访问次数,画图理解一下:
如果不内存对齐,CPU访问时,一般访问4的整数倍个字节,
访问i时,从i的起始位置访问四个字节,取出第一个字节,但是访问b时也是从i开始取4个字节,此时b 的内存还没取完,还要接着再取四个字节,将第一次提取的后三个字节和第二次提取的第一个字节合起来就是b的值,这样访问b时就多访问了一次。
如果结构体内还有更多的数据,就会让访存次数增加很多,从而影响效率。
(2),什么是内存对齐
通过牺牲空间换取效率的方案就是内存对齐,我们可以改变数据在内存中的存储方式
如图理解:
访问i时,访问四个字节,访问b时从i的结束,直接访问四个字节就可以得到b的内容,这样就减少了访问次数,牺牲了一部分空间,这就是内存对齐。
(3)如何内存对齐
struct S1
{
char c1;
int i;
char c2;
}y;
你们觉得大小是 6个字节吗?其实他不是,是12个。
struct S2
{
char c2;
char c1;
int i;
}x;
是不是觉得跟上边的结构体大小一样?不,他的大小是8,
下边讲解一下如何按照内存对齐计算结构体大小:
1)第一个成员在与结构体变量在偏移量为0的地址处。(也就是第一个成员不需要对齐)。(偏移量是相对第一个元素的位置)
2)其他成员需要对齐到某个数字(对齐数)的整数倍的地址处。
对齐:我的起始偏移量是否能整除我的对齐数。
对齐数:编译器默认的一个对齐数与该成员大小的较小值。(对齐数一般是自身的大小,一般编译器没有默认对齐数,但是可以设置)。
3)结构的总大小是最大对齐数的整数被(所有成员的的对齐数比较)
4)如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍,结构体的整体大小就是所有对齐数(包含嵌套的结构体)的整数倍。
再看这个例子:
struct S2
{
char c2;
char c1;
int i;
}x;
在内存中先放c2 (一个字节),再c1(偏移量:1)对齐数:1,可以整除,直接放(1个字节),接着放 i ,偏移量:2,对齐数 :4
不能整除,需要将i 偏移2 个字节,占(2+4)个字节,三个总和,可以整除最大对齐数,所以总大小是8。
如图:
再举两个例子:
如果结构体中有数组,数组中元素大小一样,只要一个元素对齐,其他的元素都可以对齐。
int main()
{
struct P
{
char g;//直接放, 占1个字节
int i[10];//偏移量 1; 对齐数:4 占 3+4*10=43 个字节
char h;//偏移量 44 对齐数:1 占1个字节
double b;//偏移量 :45 对齐数:8 占3+8=11 个字节
float c;//偏移量 56:对齐数:1 占1个字节
}x;//总大小57 ,最大对齐数 8,不能整除8,最后的大小是64
printf("%d", sizeof(struct P));
return 0;
}
再举一个结构体自应用的例子:
int main()
{
struct p1
{
char c;//1
double f;//7+8
int i;//4
};//总大小20 ,最大对齐数 8,不能整除8,最后的大小是24
struct p2
{
int i;//4字节
struct p1 x;//偏移量 4:最大对齐数 8,占4+24
double f;//偏移量 40,对齐数8,占8个字节
short k;//偏移量 48,对齐数2,占2个字节
};// 总大小是42 ,最大对齐数 8, 不能整除8,最后的大小是48
printf("p1 = %d\n", sizeof(struct p1));
printf("p2 = %d", sizeof(struct p2));
return 0;
}