前言:内容包括:计算结构体大小的详解,修改默认对齐数,位段
结构体的对齐规则:
所有的第一个成员变量都是从偏移量为0的位置开始存放的,直接存
实例:
1 结构体大小:12
struct S1
{
//默认对齐数:8
char c1;//对齐数:1 因为1(c1的大小,1字节)<8(默认对齐数)
int i;//对齐数:4 因为4(i的大小,4字节)<8(默认对齐数)
char c2;//对齐数:1
//最大对齐数:4
};
int main()
{
printf("%d\n", sizeof(struct S1));
return 0;
}
右边的数字代表偏移量
2 结构体大小:8
struct S2
{
char c1;//对齐数:1
char c2;//对齐数:1
int i;//对齐数:4
//最大对齐数:4
};
printf("%d\n", sizeof(struct S2));
3 结构体大小:16
struct S3
{
double d;//对齐数:8
char c;//对齐数:1
int i;//对齐数:4
//最大对齐数:8
};
int main()
{
printf("%d\n", sizeof(struct S3));
return 0;
}
c的对齐数是1,任何数字都是1的倍数,故而c可以存放在8偏移处
i的对齐数是4,而9,10,11都不是4的倍数,故而i要在12偏移处才开始存放
4 结构体大小:32
struct S3
{
double d;//对齐数:8
char c;//对齐数:1
int i;//对齐数:4
//最大对齐数:8
};
struct S4
{
char c1;//对齐数:1
struct S3 s3;//对齐数:8(因为结构体s3的所有成员中的最大对齐数是8)大小16字节,实例3已经算过
double d;//对齐数:8
//最大对齐数:8
};
int main()
{
printf("%d\n", sizeof(struct S4));
return 0;
}
为什么存在内存对齐:
1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
定类型的数据,否则抛出硬件异常
2. 性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访
问
访问未对齐的内存:
访问对齐的内存:
总体来说:
结构体的内存对齐是拿空间换取时间的做法
设计结构体的时候,既要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量集中在一起
//例如:
struct S1
{
char c1;
int i;
char c2;
};//结构体大小:12
struct S2
{
char c1;
char c2;
int i;
};//结构体大小:8
int main()
{
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}
显然第二个结构体大小更加节省空间
修改默认对齐数:
#pragma pack(数字)修改默认对齐数
#pragma pack() 还原默认对齐数
#pragma pack(8)//设置默认对齐数为8
struct S1
{
char c1;
int i;
char c2;
};//结构体大小:12
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{
char c1;
int i;
char c2;
};//结构体大小:6
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}
结构在对齐方式不合适的时候,我们可以自己更改默认对齐数
位段:
位段的声明和结构是类似的
位段的成员名后边有一个冒号和一个数字
比如:
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
数字代表:比特位
1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段
内存分配:
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;
可以看到在vs中前3个字节的内容是:62 03 04
位段的跨平台问题:
1. int 位段被当成有符号数还是无符号数是不确定的。
2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机
器会出问题。
3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是
舍弃剩余的位还是利用,这是不确定的
跟结构相比,位段可以达到同样的效果,可以很好的节省空间,但是有跨平台的问题存在