注:图片中蓝色圆圈表示空闲的字节空间,黄色表示成员占有的字节空间
编译器一般默认4字节对齐,当然也有8字节对齐的,但是如果结构体没有使用8字节的数据类型,其实也可以认为是4字节对齐
1.规则1:
结构体成员的内部偏移量(内部地址)要被这个成员的数据类型的大小整除!
typedef struct tmp
{
char a;
short b;
int c;
}test;
int main(void) {
printf("结构体大小:%d\n", sizeof(test01));
printf("成员a的地址:%p,成员b的地址:%p,成员c的地址:%p\n",&test01.a,&test01.b,&test01.c);
}
2.规则2:
整个结构体的大小,必须是最大成员size的整数倍否则就需要再末尾补充空白字节
typedef struct tmp
{
char a;
short b;
double c;
int d;
}test
int main(void) {
test test01;
printf("结构体大小:%d\n", sizeof(test01));
printf("成员a的地址:%p,成员b的地址:%p,成员c的地址:%p,成员d的地址:%p\n",&test01.a,&test01.b,&test01.c, &test01.d);
}
3.规则3:
对于结构体中的结构体,按照结构体展开之后的内存对齐来处理
typedef struct tmp01
{
char a;
char b;
char c;
}test02;
typedef struct tmp
{
char a;
short b;
test02 test02;
}test;
int main(void) {
test test01;
printf("结构体大小:%d\n", sizeof(test01));
printf("成员a的地址:%p,成员b的地址:%p,嵌套结构体成员a的地址:%p,嵌套结构体成员b的地址:%p,嵌套结构体成员c的地址:%p\n",&test01.a,&test01.b,&test01.test02.a,&test01.test02.b,&test01.test02.c);
}
4.规则4:
认为指定特殊的对齐规则,使用 #pragma pack(n),指定每个成员的起始地址,按照n来对齐,覆盖第一条规则。
#pragma pack(2)//一般编译器默认4字节对齐
//此处才用2字节对齐此结构体大小为8字节,如果为4字节对齐此结构体大小为12字节
typedef struct tmp
{
char a;
int b;
short c;
}test;
int main(void) {
test test01;
printf("结构体大小:%d\n", sizeof(test01));
printf("成员a的地址:%p,成员b的地址:%p,成员c的地址:%p\n",&test01.a,&test01.b, &test01.c);
}
注意:如果这个n比第一条规则对齐还要大,那么就取小的
#pragma pack(8)//此时8字节对齐,大家可能会以为此时结构体大小为16或者24字节
//但此时结构体中最大数据类型为int所以取小的,按照规则1进行,所以此时结构体大小为12字节
typedef struct tmp
{
char a;
int b;
short c;
}test;
int main(void) {
test test01;
printf("结构体大小:%d\n", sizeof(test01));
printf("成员a的地址:%p,成员b的地址:%p,成员c的地址:%p\n",&test01.a,&test01.b, &test01.c);
}
5.规则5:
可以使用 #pragma pack(1) 使结构体不进行任何对齐,直接码放数据
#pragma pack(1)
typedef struct tmp
{
char a;
int b;
short c;
}test;
int main(void) {
test test01;
printf("结构体大小:%d\n", sizeof(test01));
printf("成员a的地址:%p,成员b的地址:%p,成员c的地址:%p\n",&test01.a,&test01.b, &test01.c);
}