1.结构体内存对齐
结构体既然有变量存在,那么就要给结构体进行内存分配,下面来深入讨论结构体内存有关的问题。
这里知识点非常重要,一定要熟透。
1.1结构体内存对齐规则
规则1:结构体的第一个成员对齐到结构体的起始位置偏移量为0的地址处。
规则2:其他成员要对齐到对齐数的整数倍的地址处。
对齐数=编译器默认的一个对齐数与该成员的较小值。
Linux中 gcc 没有默认对齐数,对⻬数就是成员自身的大小。
规则3:结构体大小为最大对齐数的整数倍。
规则4: 如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最打对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。
下面举两个例子:
struct S1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));
struct S2
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct S2));
上面代码中输出结果:
2.2为什么存在内存对齐
2.3修改默认对齐数
编译器中默认的对齐数我们也是可以对其进行修改的:
#include <stdio.h>
#pragma pack(1)//设置默认对⻬数为1
struct S
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的对⻬数,还原为默认
int main()
{
//输出的结果是什么?
printf("%d\n", sizeof(struct S));
return 0;
}
2.结构体传参
结构体传参时也是很有讲究的,比如下面一段代码:
struct S
{
int data[1000];
int num;
};
struct S s = {{1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
print1(s); //传结构体
print2(&s); //传地址
return 0;
}
是用print1好还是用print2好呢?
肯定是print2更加
3.结构体实现位段
3.1位段是什么
位段和结构体有两个不同:
char ,在C99中位段成员的类型也可以选择其他类型。
2.位段的成员名后边有⼀个冒号和⼀个数字。
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
上面代码中就是一个位段的声明,而冒号后面的数值则表示该成员的占用内存大小,单位是字节。
3.2位段的内存分配
struct S
{
char a:3;
char b:4;
char c:5;
char d:4;
};
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;
内存分配: