前言
根据之前讲了结构体的《声明》、《创建》、《初始化》、《结构体内存对齐》。 接下来我们就来深入探讨结构体
问题:那么有没有考虑结构体嵌套结构体的内存对齐呢?
一、结构体的内存对齐之深入理解
示例:
struct S3
{
double d;
char c;
int i;
};
struct S4
{
char c1;
struct S3 s3;
double d;
};
int mian()
{
struct S4 s4 = { 0 };
printf("%zd\n", sizeof(s4));
return 0;
}
根据规则4:如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员最大对齐数的整数辈出,结构体的整体大小就是所有最大对齐数(包含嵌套结构体中成员对齐数)的整数倍。
那么根据以上代码:
s3就对应其中成员最大对齐数为double类型(8)
再根据规则1、2、3就可以得出这个结构体的大小
为什么存在内存对齐?
修改默认对齐数
#pragma 这个预处理指令,可以改变编译器的默认对齐数。
#pragma pack(1)//把默认对齐数定义为1
struct S
{
char c;
int i;
char a;
};
int main()
{
printf("%zd\n", sizeof(struct S));
return 0;
}
二、结构体传参
2.1:该怎么传参呢?
代码如下(示例):
struct S
{
int arr[1000];
int n;
double b;
};
void print1(struct S tmp)
{
int i = 0;
for (i = 0;i < 5;i++)
{
printf("%d", tmp.arr[i]);
}
printf("%d\n", tmp.n);
printf("%lf\n", tmp.b);
}
int main()
{
struct S s = { {1,2,3,4,5},100,3.14 };
print1(s);//这里s里面的数组arr[1000](空间大),但是传参过去时会有空间的浪费
return 0;
}
这里s里面的数组arr1000,但是传参过去时会有空间的浪费,那么我们用地址来传
同时我们也可以达到同样的效果
修正:
struct S
{
int arr[1000];
int n;
double b;
};
void print1(struct S* tmp)
{
int i = 0;
for (i = 0;i < 5;i++)
{
printf(“%d”, tmp->arr[i]);
}
printf(“%d\n”, tmp->n);
printf(“%lf\n”, tmp->b);
}
int main()
{
struct S s = { {1,2,3,4,5},100,3.14 };
print1(&s);
return 0;
}
三、结构体实现位段
3.1什么是位段
比如:
struct S
{
int_a:2;//位段结构、4个字节----32个bit
int_b:5;//位段结构、4个字节----32个bit
int_c:10;//位段结构、4个字节----32个bit
int_d:30;//位段结构、4个字节----32个bit
};
int main()
{
return 0;
}首先: 位段中的位是二进制位
那么0就可以用2个bit来表达00
1-----------2---------------01
2-----------2---------------10
3…以此类推
这样可以节省很多空间
节省内存
那么位段是怎么分配内存的呢?
位段的内存分配
3.2
根据以下图片分析:
每次申请1个字节(8个bit位)这里采用了从右向左,浪费操作。
按照16进制来表达时:0x620304。
浪费的bit用0来填补
例子:
根据上面的图片可知:
当不够你所要申请的空间,那么就会重新开辟一个空间来容纳你的空间
(如:第一个a申请了2个bit,第二个申请了5个bit,第三个申请10个bit,而第四个要30个bit,那就在申请一个空间来容纳第四个空间!)
位段的跨平台问题
在16位int是2个字节!!!
如果我们把16位看成32位那么这样就会产生不同结果!!!
所以位段是不跨平台的。
总结
1:结构体内存对齐----浪费空间来促进时间;
2:位段-------节省内存;
3:跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在