本篇文章将详细介绍一下怎样计算一个结构体的大小,什么是对齐数
并且会在Windows系统中进行演示
1、对齐数
要计算一个结构体的大小,首先来介绍一个概念 : 什么是对齐数 ?
对齐数 = 编译器默认的对齐数 与 该成员大小 的较小值
在vs中,编译器的默认对齐数是8,根据编译器的不同,默认对齐数会有所差异
2、结构体大小计算规则
3、练习
struct test1
{
char a;
int b;
char c;
};
struct test2
{
char a;
short b;
int c;
};
struct test3
{
double a;
char b;
int c;
};
struct test4
{
char a;
struct test3 b;
int c;
};
test1
char的大小是1,int的大小是4,所以char类型的变量a、c的对齐数是min(8, 1) = 1,int类型的变量b的对齐数是min(8, 4) = 4
首先来看第一个规则,第一个成员变量a在与结构体变量偏移量为0的地址处
然后第二个变量b对齐到它的对齐数4的整数倍地址处,所以abc三个变量占用了0-8共九个位置
但是结构体整体的最大对齐数是int变量b的对齐数大小也就是4,所以结构体整体大小必须是为4的整数倍
故test1结构体的大小为12
test2
char的大小是1,short的大小是2,int的大小是4,所以char类型的变量a的对齐数是min(8, 1) = 1,short类型的变量b的对齐数是min(8, 2) = 2,int类型的变量c的对齐数是min(8, 4) = 4
故test2的结构体大小为8
test3
double的大小是8,char的大小是1,int的大小是4,所以double类型的变量b的对齐数是min(8, 8) = 8,char类型的变量a的对齐数是min(8, 1) = 1,int类型的变量c的对齐数是min(8, 4) = 4
故test3的结构体大小为16
test4
test4结构体嵌套了结构体test3,而test3的最大对齐数是double变量的对齐数也就是8,所以b变量要从8位置开始,test4结构体整体的最大对齐数也是b变量test3结构体中的8,所以test4的结构体大小需为8的整数倍
故test3的结构体大小为32
4、修改默认对齐数
不同的编译器有不同的默认对齐数,但是在实际使用中有时可能需要自己设置需要的对齐数,这时就要使用#pragma这个预处理指令了。
#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct test1
{
char a;
int b;
char c;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct test2
{
char a;
int b;
char c;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
//输出的结果是什么?
printf("%d\n", sizeof(struct test1));
printf("%d\n", sizeof(struct test2));
return 0;
}
输出的结果是12和6,相同的结构体,默认对齐数不同结构体大小也会发生变化
5、为什么要内存对齐
简单来说就是,为了方便查找数据,结构体的内存对齐用空间换取了时间