结构体内存对齐与联合体

目录

前言

结构体大小的计算

修改默认对齐数


前言

当我们了解结构体的声明,结构体的自引用,结构体变量的定义和初始化,如何计算结构体的大小呢?结构体类型的数据是在内存中如何存放的呢?这也是本文需要讨论的问题;

结构体大小的计算

//结构体声明
struct n
{
	char c1;
	int i;
	char c2;
};

int main()
{
	struct n n1;
    //计算结构体的大小
	printf("%d\n", sizeof(n1));
	return 0;
}

char-字符类型-大小为1字节   int - 整型 - 大小为4字节,那么总大小是不是 1+4+1=6字节呢?

运行结果:

结果是12个字节,为什么?这就不得不涉及结构体内存对齐规则;

结构体内存对齐规则

1. 结构体第一个成员变量存放在与结构体变量偏移量为0的地址处

2. 其他成员变量要对齐到对齐数的整数倍的地址处;

    对齐数=编译器默认对齐数与成员变量大小的较小值;

  vs默认对齐数为8字节,linux环境没有默认对齐数,对齐数就是成员自身的大小

3. 结构体总大小为最大对齐数的整数倍

4. 对于嵌套结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

接下来的讨论,全是在vs编译环境下,即默认对齐数为8; 假设创建结构体变量n1从0x0000ff40处开辟内存空间,示意图如下

结构体内存对齐与联合体_第1张图片

 根据结构体对齐第一条规则:结构体第一个成员变量存放在与结构体变量偏移量为0的地址处;

  结构体成员变量c1就应该存放于偏移量为0的地址处,且占1byte; 如上图c1的位置;

根据结构体对齐第二条规则:其他成员变量要对齐到对齐数的整数倍的地址处;

1. 先计算对齐数 int在内存中占4个字节,默认对齐数为8个字节,对齐数为自身大小和默认对 齐数两者较小值 那么对齐数=4;结构体第二个成员变量就要对齐到4的整数倍,即偏移量等于4的位置,且占4byte,如上图i的位置;

2. 计算对齐数  har在内存中占1个字节,默认对齐数为8个字节,对齐数为自身大小和默认对 齐数两者较小值 那么对齐数=1;结构体第二个成员变量就要对齐到1的整数倍,即偏移量等于8的位置,且占1byte,如上图c2的位置;

 根据结构体对齐第三条规则:结构体总大小为最大对齐数的整数倍

 第一个对齐数=4,第二个对齐数=1 最大对齐数=4;结构体总大小=4*j (j=1,2,....)

已经用掉9个字节,下一个4的整数倍即偏移量为11的位置,12个字节;如上图绿色方框所示;

综上,已经分析出结果为12字节,那分析步骤是否如同我们如上所述,需要进行进一步验证

offsetof() - 宏 头文件 #include

返回值为unsigned int ,第一个参数为结构体变量类型,第二个参数为成员变量名;

计算结构体成员相对于起始位置的偏移量

结构体内存对齐与联合体_第2张图片

 验证如下:

# include 
struct n
{
	char c1;
	int i;
	char c2;
};
int main()
{
	printf("%u\n", offsetof(struct n, c1));
	printf("%u\n", offsetof(struct n, i));
	printf("%u\n", offsetof(struct n, c2));
	return 0;
}

运行结果:

 验证结果如上图所示,与示意图完美匹配,可以得出分析步骤完全正确;

当我们计算嵌套结构体的大小,如下计算n的大小,结果又是如何?

struct s
{
	double d;// 对齐数1=8;
	char c;//对齐数2=1;
	int i;//对齐数3=4;
};
//嵌套结构体最大对齐数=8字节;
//struct s的总大小经计算为16个字节

struct n
{
	char c1;//对齐数4=1;
	struct s n1;
	double d;//对齐数5=8;
};
int main()
{
	printf("%d\n", sizeof(struct n));
	return 0;
}

根据结构体对齐的第四条规则:对于嵌套结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍;

不难得出结论,结果为32字节;

修改默认对齐数

使用 # pragma预处理指令来修改默认对齐数

# pragma pack(1)//设置默认对齐数为1;
struct n
{
	char c1;
	int i;
	char c2;
};
# pragma pack()//取消设置的默认对齐数,还原为默认;
int main()
{
	printf("%d\n", sizeof(struct n));
	return 0;
}

运行结果:

联合体

联合体定义

C语言中,变量的定义是分配存储空间的过程。一般的,每个变量都具有其独有的储存空间,那么是否可以在同一块存储空间储存不同的数据类型呢?

联合体也叫共用体,C语言中联合体的关键字是union,这种类型定义的变量也包含一些列的成员变量,特征是这些成员共用同一块内存空间;

//定义联合类型的声明
union 联合名
{
   成员列表;
};

验证过程:验证联合体成员是否共用同一块内存

union un
{
	char c;
	int i;
};
int main()
{
	union un u;
	printf("%p\n", &u);
	printf("%p\n", &(u.c));
	printf("%p\n", &(u.i));
	return 0;
}

运行结果:

 联合体大小的计算

联合体成员是共用同一块内存空间,一个联合变量的大小至少是最大成员的大小(因为联合体至少得有能力保存最大的成员变量);

//计算联合体的大小
union un
{
	char c;
	int i;
};
int main()
{
	union un u;
	printf("%d\n", sizeof(u));
	return 0;
}

运行结果:

但是联合体的大小一定是最大的成员的大小吗?

union un
{
	char arr[5];
	int i;
};
int main()
{
	union un u;
	printf("%d\n", sizeof(u));
	return 0;
}

运行结果:

 结果是8个字节,成员变量最大为int类型,只占4个字节,所以联合体变量的大小不一定是最大成员的大小;

联合体大小的计算

  • 联合体的大小至少是最大成员的大小;
  • 当最大成员大小不是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍处;

结构体内存对齐与联合体_第3张图片 共用体从0偏移量处开始共用同一块内存空间,c为字符数组,数组成员为char,char占1个字节,vs默认对齐数为8,所以对齐数1=1;i为整型数据,占4个字节,vs默认对齐数为8所以对齐数2=8;所以最大对齐数=4;此时内存使用5个字节,但是要对齐到最大对齐数的整数倍的位置,即相对于起始位置的第8个字节处,即偏移量为7的位置,所以占用内存的大小为8字节;

 

你可能感兴趣的:(c++,算法,开发语言)