C语言 结构体(联合体)对齐规则

时间:2022-05-21 13:16:13
/* 结构体(联合体)对齐规则 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /*
* 原则1、第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。 * 原则2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最宽基本类型大小的整数倍地址开始存储。 *原则3、结构体的总大小为结构体最宽基本类型成员(成员可以是基本类型,也可以是结构体)大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节 *最宽基本类型的概念,所谓基本类型是指像char、short、int、float、double这样的内置数据类型。 */ struct Data1
{
int c;
char a;
char b;
}; /*
struct Data1分析
分析对齐数
对齐数的值是 结构体中最宽基本类型成员
struct Data1最宽类型是int,占4个字节大小,所以对齐数的值是4 根据原则1(第一个数据成员放在offset为0的地方),成员属性c从offset为0的位置开始,成员属性c大小是4个字节,成员属性c从offset为0的位置开始存储,占据4个字节大小 成员属性a从offset为4的位置开始,根据原则1(以后每个数据成员存储的起始位置要从该成员大小的整数倍开始) ,现在offset是4,是1的整数倍
所以成员属性a从offset为4的位置开始存储,占据1个字节大小 成员属性b从offset为5的位置开始,根据原则1(以后每个数据成员存储的起始位置要从该成员大小的整数倍开始) ,现在offset是5,是1的整数倍
所以成员属性b从offset为5的位置开始存储,占据1个字节大小 现在struct Data1一共占据6个字节大小的空间,根据原则3(必须是其内部最大成员的整数倍),struct Data1最宽基本类型是int,占4个字节大小
因此结构体的总大小必须是4的倍数,6不是4的倍数,补齐2个字节,变成8个字节
结论:struct Data1 大小是8个字节 */ struct Data2
{
char a;
int c;
char b;
}; /*
struct Data2分析
分析对齐数
struct Data2最宽类型是int,占4个字节大小,所以对齐数的值是4 根据原则1(第一个数据成员放在offset为0的地方),成员属性a从offset为0的位置开始,成员属性a大小是1个字节,成员属性a从offset为0的位置开始存储,占据1个字节大小 成员属性c是int类型,根据原则1(以后每个数据成员存储的起始位置要从该成员大小的整数倍开始),现在offset是1,1不是4的整数倍
编译器填充3个字节,现在offset为4 , 4是int的整数倍,成员属性c从offset为4的位置开始存储,占据4个字节大小 成员属性b从offset为8的位置开始,根据原则1(以后每个数据成员存储的起始位置要从该成员大小的整数倍开始) ,现在offset是8,是1的整数倍
所以成员属性b从offset为8的位置开始存储,占据1个字节大小 现在struct Data2一共占据9个字节大小的空间,根据原则3(必须是其内部最大成员的整数倍),struct Data2最宽基本类型是int,占4个字节大小
因此结构体的总大小必须是4的倍数,9不是4的倍数,补齐3个字节,变成12个字节
结论:struct Data1 大小是12个字节 */ struct Data3
{
char a;
short b;
double c;
}; /*
struct Data3分析
分析对齐数
struct Data3最宽类型是double,占8个字节大小,所以对齐数的值是8 根据原则1(第一个数据成员放在offset为0的地方),成员属性a从offset为0的位置开始,成员属性a大小是1个字节,成员属性a从offset为0的位置开始存储,占据1个字节大小 成员属性b从offset为1的位置开始,根据原则1(以后每个数据成员存储的起始位置要从该成员大小的整数倍开始) ,现在offset是1,不是short的整数倍
编译器填充1个字节,现在offset为2 , 2是short的整数倍,成员属性b从offset为2的位置开始存储,占据2个字节大小 成员属性c从offset为4的位置开始,根据原则1(以后每个数据成员存储的起始位置要从该成员大小的整数倍开始) ,现在offset是4,不是double的整数倍
编译器填充4个字节,现在offset为8 , 8是double的整数倍,成员属性c从offset为8的位置开始存储,占据8个字节大小 现在struct Data3一共占据16个字节大小的空间,根据原则3(必须是其内部最大成员的整数倍),struct Data3最宽基本类型是double,占8个字节大小
因此结构体的总大小必须是8的倍数,16是8的倍数,不用填充字节
结论:struct Data3 大小是16个字节 */ struct Data4
{
short a;
char b;
double c;
char d[];
}; /*
struct Data4分析
分析对齐数
struct Data3最宽类型是double,占8个字节大小,所以对齐数的值是8
char d[5]并非基本类型 根据原则1(第一个数据成员放在offset为0的地方),成员属性a从offset为0的位置开始,成员属性a大小是2个字节,成员属性a从offset为0的位置开始存储,占据2个字节大小 成员属性b从offset为2的位置开始,根据原则1(以后每个数据成员存储的起始位置要从该成员大小的整数倍开始) ,现在offset是2,是1的整数倍
成员属性b从offset为2的位置开始存储,占据1个字节大小 成员属性c从offset为3的位置开始,根据原则1(以后每个数据成员存储的起始位置要从该成员大小的整数倍开始) ,现在offset是3,不是double的整数倍
编译器填充5个字节,现在offset为8 , 8是double的整数倍,成员属性c从offset为8的位置开始存储,占据8个字节大小 成员属性d从offset为16的位置开始,根据原则1(以后每个数据成员存储的起始位置要从该成员大小的整数倍开始) ,现在offset是16,是char的整数倍
成员属性d从offset为16的位置开始存储,占据1个字节大小 现在struct Data4一共占据17个字节大小的空间,根据原则3(必须是其内部最大成员的整数倍),struct Data3最宽基本类型是double,占8个字节大小
因此结构体的总大小必须是8的倍数,17不是8的倍数,需要填充7个字节
结论:struct Data4 大小是24个字节 */ struct Data5
{
short a;
struct Data4 b;
}; /*
struct Data5分析
分析对齐数
根据原则2, struct Data4最宽类型是double 占8个字节大小,而struct Data5成员a占2个字节,所以对齐数的值是8 根据原则1(第一个数据成员放在offset为0的地方),成员属性a从offset为0的位置开始,成员属性a大小是2个字节,成员属性a从offset为0的位置开始存储,占据2个字节大小 成员属性b从offset为2的位置开始,根据原则2(结构体成员要从其内部最大元素大小的整数倍地址开始存储) ,现在offset是2,不是double的整数倍
编译器填充6个字节,现在offset为8 , 8是double的整数倍,成员属性b从offset为8的位置开始存储,占据24个字节大小 现在struct Data5一共占据32个字节大小的空间,根据原则3(必须是其内部最大成员的整数倍),struct Data5最宽基本类型是double,占8个字节大小
因此结构体的总大小必须是8的倍数,32是8的倍数,不需要填充字节
结论:struct Data5 大小是32个字节 */ struct Data6
{
double a;
struct Data1 b;
}; /*
struct Data6分析
分析对齐数
根据原则2, struct Data1最宽类型是int 占4个字节大小,而struct Data5成员a 占8个字节,所以对齐数的值是8 根据原则1(第一个数据成员放在offset为0的地方),成员属性a从offset为0的位置开始,成员属性a大小是8个字节,成员属性a从offset为0的位置开始存储,占据8个字节大小 成员属性b从offset为8的位置开始,根据原则2(结构体成员要从其内部最大元素大小的整数倍地址开始存储) ,现在offset是8 ,是 int 的整数倍
成员属性b从offset为8的位置开始存储,占据8个字节大小 现在struct Data6一共占据16个字节大小的空间,根据原则3(必须是其内部最大成员的整数倍),struct Data6最宽基本类型是double,占8个字节大小
因此结构体的总大小必须是8的倍数,16是8的倍数,不需要填充字节
结论:struct Data6 大小是16个字节 */ void test()
{
printf("----struct size---1-[%d]------\n", sizeof(struct Data1)); //
printf("----struct size--2--[%d]------\n", sizeof(struct Data2)); //
printf("----struct size--3--[%d]------\n", sizeof(struct Data3)); //
printf("----struct size--4--[%d]------\n", sizeof(struct Data4)); //
printf("----struct size--5--[%d]------\n", sizeof(struct Data5)); //
printf("----struct size--6--[%d]------\n", sizeof(struct Data6)); //
} int main()
{
test();
printf("-----ok------\n");
getchar();
return ;
}