c语言---结构体内存对齐计算

文章链接:https://codemouse.online/archives/2020-03-12223953

结构体内存对齐
  • 元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每个元素放置到内存中时,它都会认为内存是按照自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始。
内存对齐的原因
  1. 平台问题(移植问题):不是所有的硬件平台都能访问任意地址上的任意数据的,某些硬件平台只能在某些地质处取某些特定类型的数据,否则跑出硬件异常。

  2. 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要做两次内存访问,而对齐的内存只需要访问一次。

总结:拿空间换时间

获取结构体中某一元素的位置

使用offsetof宏来判断结构体中成员的偏移地址,在stddef.h中定义

 #define offsetof(type,menber) (size_t)&(((type*)0)->member)
 // 由于从0处算,那么获取到的结构体元素地址也就是他所在结构体的偏移值
设置默认对齐数
#pragma pack(value)   //value只能是1,2,4,8,16
#pragma pack()    //设置为默认对齐数

结构体内存对齐规则
  1. 第一个成员在与结构体变量偏移量为0的地址处。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS中默认的值为8, Linux中的默认值为4
  3. 结构体总大小为默认对齐数或者设置的对齐数的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,最后结构体的整体大小就是默认对齐数的整数倍。
举例

环境:32位机
默认char一字节,short二字节,int,float四字节,double八字节

struct A{
	char a;
	int b;
	float c;
	double d;
	int e;
};

解析:
对齐数为4:
a为首个成员,从0出开始,
b大于等于对齐数,要在新的内存单位开始,也就是4处,
cde同理.大小为24刚好为默认对齐数的整数倍,所以最后大小为24.

QQ截图20200312222207

对齐数为8:
a为首个成员,从0出开始,
b小于默认对齐数,自身大小作为对齐数,则存放在4处,
c同理,则存放在8处,
d大小等于对齐数,存放在8的整数倍上,所以移动到了16处存放,
e小于对齐数,自身大小作为对齐数,则存放在16+8=24处,那么总大小为28,
但由于结构体大小必须为默认对齐数的整数倍,所以总大小为32.

QQ截图20200312221655
添加上结构体嵌套,这次默认对齐数为8

 struct A{
	char a;
	int b;
	float c;
	double d;
	int e;
};
struct B{
	char a;
	short b;
	struct A c;
	struct A d[2];
	struct A* e;
};
  • 解析:
    a为首个成员,从0出开始,
    b小于默认对齐数,自身大小作为对齐数,则存放在2处,
    c大小大于对齐数,存放在对齐数的整数倍上,所以移动到了8处存放,
    d与c同理,则存放在8+32=40处,
    e存放在40+2*32=104处,
    总大小为108,
    但由于结构体大小必须为默认对齐数的整数倍,所以总大小为112.
验证程序
#pragma pack(8)
#include <stdio.h>
#include <stddef.h>
struct A{
	char a;
	int b;
	float c;
	double d;
	int e;
};
struct B{
	char a;
	short b;
	struct A c;
	struct A d[2];
	struct A* e;
};
void main()
{
	struct B a = { 0 };
	printf("%d \n", offsetof(struct B, a));
	printf("%d \n", offsetof(struct B, b));
	printf("%d \n", offsetof(struct B, c));
	printf("%d \n", offsetof(struct B, d));
	printf("%d \n", offsetof(struct B, e));
	printf("sum=%d \n",sizeof(a));
}


QQ截图20200312223801

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值