struct 结构体的内存对齐

💙作者:阿润菜菜

📖专栏:一起学习C言


本文目录

在内存中观察 

结构体内存对齐的规则:

为什么存在内存对齐?

编程中我们该如何设计结构体?

修改默认对齐数

相关笔试题


在内存中观察 

首先我们来看一段代码:这里有两个结构体,只有成员顺序不一样

//1
struct S1
{
 char c1;
 int i;
 char c2;
};

//2
struct S2
{
 char c1;
 char c2;
 int i;
};

那么你们觉得S2大小是几个字节?S1又是多少?

作为C语言初学者一般是这样认为的:char 1字节 int 4字节 所以都是6字节

​但实际上结果不是这样的,为什么呢?下面我们就来看看结构体内存对齐的知识:

如图,假设0为结构体S1在内存中的首地址,顺序123...为相对于首地址的偏移量(宏 offsetof  用来计算结构体成员相对于起始位置的偏移量)

​通过offsetof可以计算出三个变量(c1,i,c2)各自对应的偏移量: 0 ,4 ,8

​我们发现,在内存中红色的空间并没有被使用,而是都被浪费掉了,同样观察结构体S2成员变量排列情况: 

通过以上,我们可以知道结构体成员变量在内存中并不是按照顺序排列的,而是按照一定的规则进行内存对齐排序的:

结构体内存对齐的规则:

  • 结构体的第一个成员直接对齐到相对于结构体变量起始位置为0的地址处
  •  从第二个成员开始,要对齐到某个【对齐数】的整数倍的偏移处
  • 对齐数:结构体成员自身大小和默认对齐数的较小值VS中默认的值为8,Linux环境默认不设对齐数)
  • 结构体的总大小,必须是最大对齐数的整数倍。每个结构体成员都有一个对齐数,其中最大的对齐数就是最大对齐数
  • 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

为什么存在内存对齐?

总体来说:结构体的内存对齐是拿空间来换取时间的做法。

1. 平台原因 ( 移植原因 )
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2. 性能原因
数据结构 ( 尤其是栈 ) 应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

编程中我们该如何设计结构体?

那在我们设计结构体的时候,我们既要满足对齐,又要节省空间: 让占用空间小的成员尽量集中在一起。
如:
//不推荐
struct S1
{
 char c1;
 int i;
 char c2;
};
//推荐
struct S2
{
 char c1;
 char c2;
 int i;
};

虽然S1S2类型的成员一模一样,但是S2所占的内存空间就少了一些

修改默认对齐数

在结构在对齐方式不合适的时候,我们可以利用#pragma 这个预处理指令更改默认对齐数:

#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
 char c1;
 int i;
 char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{
 char c1;
 int i;
 char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认

相关笔试题

1. 如下C程序,在64位处理器上运行后 sz 的值是什么( )

 正确答案:B
要注意的是64位的情况下指针是占8个字节的,剩余详细了解结构体内存对齐的规则

2.结构体的大小分别是:

 3.百度笔试题: 写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明

#define  STRUCT_OFFSET(id, element)  ((unsigned long)(&(( struct id*)0)->element))
考察: offsetof 宏的实现
因为是求偏移量 所以假设结构体的首地址是0开始,把他转换成结构体指针类型,在用 -> 取得他的成员,前面加了一个& 就是取得这个成员的 地址,最后在强制转换成unsigned long, 这样就得到了偏移量。

本节完 

  • 22
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 24
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吉始

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值