struct 结构体的内存对齐

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

💙作者阿润菜菜

📖专栏一起学习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中默认的值为8Linux环境默认不设对齐数
  • 结构体的总大小必须是最大对齐数的整数倍。每个结构体成员都有一个对齐数其中最大的对齐数就是最大对齐数
  • 如果嵌套了结构体的情况嵌套的结构体对齐到自己的最大对齐数的整数倍处结构体的整体大小就是所有最大对齐数含嵌套结构体的对齐数的整数倍。

为什么存在内存对齐

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

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.百度笔试题 写一个宏计算结构体中某变量相对于首地址的偏移并给出说明

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

本节完 

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6