结构体为何要进行对齐以及如何对齐

2023-05-16

先说如何对齐,再讲讲其背后的原理。对齐规则在网上和书上都很容易找到。无非就是以下几点。

规则

1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
(VS中默认的值为8)
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍
处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数
倍。
5、结构体中定义变量时最好占用字节数从小到大依此定义,可以使得结构体占用空间最小。
 

用几个例子来解释几条规则:

struct st{  

    int8_t  b;  

    int32_t a;  

    char c;

    float d;

    char e;

};  

 根据第一条规则,int8从偏移量为0的地址开始存。

根据第二条规则,int32是四个字节大小,所以对齐数是4。所以他开始的地址应该是4的整数倍,依次存储的话,那就只能从4位置开始了,中间有三个空格用于对齐。接着存char,char占一个字节,所以对齐数是1,前面已经用了8个字节了,8是1的倍数,所以紧接着存放char.最后存float,float占4个字节,最大对齐数4,abc三个变量物理存储已经连续占用了了9(1+3+4+1)个字节,9不是4的倍数,最近的12是4的倍数,所以float从偏移量12位置开始存。最后一个char占一个字节,对齐数1,目前已经连续占用的物理空间是(1+3+4+1+3+4)16个,16是1的倍数,所以紧接着存char。

根据第三条规则,目前已经连续占用的物理空间是(1+3+4+1+3+4)17个字节。st结构体中最大对齐数是4,17不是4的倍数,最近的20是4的倍数。所以该结构体最后又占用了3个空间。

最后总结,一共占用了20个字节。

下图一个空格表示一个字节

接下来讲嵌套

struct sstt{  

    char a;

    struct {

        char b;

        int c;

     } pp;

    float d;

};  

先看pp结构体占用几个字节,b占用1个字节,占用4个字节,但是1不是4的整数倍,所以中间空了3个字节,一共8个字节,这个结构体中最大对齐数是int c(4个字节),8是4的倍数。最后得出pp一共占用8个字节。

根据第四条规则、然后再看sstt,char a占一个字节,但是pp从哪里开始呢。pp结构体中最大对齐数是int c(4个字节),所以要从4的倍数开始存,那就是char a后面再空3个空格存pp,此时1+3+8,到目前为止一共占用了12个字节,接着存float,float占4个字节,即接着存float.所以一共是16个字节。最后整结构体包括嵌套结构体中最大的对齐数是4,而16是4的倍数,正好。

最后总结,一共占用了16个字节。

如果结构体中的成员包括数组或者其他结构体,在数据对其时,要以结构体中最深层的基本数据类型为准。即看数组存的什么数据类型。

借此机会我们一起把第五条规则讨论一下。

struct sstt{  

    char a;

    int b[2][3];

    char c; 

};  

struct sstt1{  

     int b[2][3];

    char a;   

    char c; 

};  

sstt结构体,char占一个字节,b基本类型是int占4个字节,所以要空3个字节再存b,b一个是2*3*4即24个字节,目前为止一共1+3+24=28个字节,c占1个字节,正好是28倍数,所以紧接着再存c,目前一共占有29个字节。由于 最大对齐数是4,即一个int大小,29不是4的倍数,补3个空字节。最2后得出占29+3=32个字节。

sstt1结构体,b占2*3*4=24字节,a占1个字节,24是1的倍数,所以紧接着存a,那目前位置一共占用1+24=25字节。同理再存c。所以目前为止占26个字节,但是最大对对齐数是4,即一个int大小,所以要再补2个字节,最有一共占28个字节。

所以得出第五条规则,按从小到大定义变量,占用字节最少。

为什么???????要这么浪费空间?????

因为在32位操作系统(虽然64位操作系统,但是为了保证兼容性,编程仍然主要考量32位)中,数据总线是32位,地址总线是32位。地址总线是32位,意味着寻址空间是按4递增的;数据总线32位意味着一次可读写4byte。

想要具体了解什么是地址总线和数据总线可以看下面链接

(44条消息) 8086/8088CPU内部结构,引脚图,物理地址与逻辑地址_Always Fighting的博客-CSDN博客_8088cpu

简单介绍一下, 以8086CPU为例,注意这是一个16位的芯片,而我们大多数使用的是32或64位cpu

地址/数据分时复用引脚AD15-AD0(39,2-16):传送地址时单向输出,传送数据时双向输入或输出。地址和数据公用引脚,分时复用。这16个引脚是一起工作的。

视线拉回我们32位cpu,32位/8位=4字节,所以cpu一次工作可以取到4个字节的数据。那以读取的角度排布我们内存的话可以像下面这样。一次cpu读一行数据。

                         

如果下面的结构体不对齐会发生什么事情,就像上面中间那张图,如果需要读取到完整的i需要读取两次(或者说两行)然后拼接再一起,I/O操作是很耗时的,这是很浪费时间的。如果需要更快读到数据,那一个数据最好是存在一整行,像上面第三张图那样。

struct stu1  
{   
   char c1;   
   int i;  
   char c2;  

 可见如果想要存一个int类型的话,那int变量的偏移量必须是4的倍数,如果是一个double或者 long long型那偏移量一定是8的倍数。即向下面的图。int类型变量可以从0、4、8、12位置开始存,short int类型可以从0、2、4、6、8、10、12、14开始存,double可以从0,8位置开始存。可能你对double类型有疑问,为什么4不行,反正double(8位)占两行,在哪都在占,我想这可能是考虑到64位机器,64位一次可以读8个字节,如果存4位置肯定会遇到换行,像下面第二张图。

                            

你可能还在想为什么不直接全部按4的倍数偏移,那可以看下面两张图。这两个方案你会选哪个。很明显是B,一次就可以读出s和c两个数据,而A读取s和c两个数据需要两次。不仅省内存还省时间。

 总结对齐原因

1. 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据
的;某些硬件平台只能 在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2. 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在
于,为了访问未对齐的 内存,处理器需要作两次内存访问;而对齐的内存访问
仅需要一次访问。
总体来说:结构体的内存对齐是拿空间来换取时间的做法。优点是提高了可移植性和cpu性能
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

结构体为何要进行对齐以及如何对齐 的相关文章

  • 常用命令汇总

    tar gz 压缩包 解压 xff1a tar zxvf FileName tar gz 压缩 xff1a tar zcvf FileName tar gz DirName 删除远程分支 span class token function
  • 问题解决:import serial提示 ImportError: No module named serial

    问题 xff1a 在Ubuntu系统中运行python脚本 xff0c 出现如下提示说明pythoh的serial模块没有安装 ImportError No module named serial 解决 网上大部分的解决方法都是安装pyse
  • An Introduction to Deep Learning for the PhysicalLayer

    An Introduction to Deep Learning for the PhysicalLayer I INTRODUCTION 这段主要讲了文章的主要工作 将发射机 通道和接收器作为一个自动编码器 xff0c 对于给定的损失函数
  • 机器学习调制解调器:ML将如何改变我们设计下一代通信系统的方式

    所以 xff0c 我听到你们都在问 xff0c 我们都失业了吗 通信工程师是机器崛起的又一个受害者吗 幸运的是 xff0c 本文中的答案是否定的 但是Nathan Ben和Tim指出了一种新的方式来指定和设计通信系统 xff0c 这可能会永
  • git clone指定分支

    技术背景 Git是代码版本最常用的管理工具 xff0c 此前也写过一篇介绍Git的基本使用的博客 xff0c 而本文介绍一个可能在特定场景下能够用到的功能 直接拉取指定分支的内容 Git Clone 首先看一下如果我们按照常规的操作去拉取一
  • PX4最新版ubuntu编译环境搭建

    PX4最新版ubuntu编译环境搭建 本博客的撰写主要也是博主的自己血泪之路 xff0c 参考了各种博客 xff0c 然而对于我并没有什么卵用 xff0c 简直是成功的都一样 xff0c 不成功的各有各的不同 xff0c 最后在快要放弃而转
  • RTOS滴答Tick设置多少才合适

    本文转载 xff0c 留作笔记 xff0c 如有侵权 xff0c 请联系删除 xff0c 原文链接地址 xff1a 嵌入式开发 RTOS滴答Tick设置多少才合适 xff1f qq com https mp weixin qq com s
  • Darknet-Deep_sort_pytorch 无人机跟踪识别记录

    创建数据集 使用labelme 构造voc数据集格式 转换txt为xml 开始训练 span class token function sudo span span class token function nohup span darkn
  • Docker安装Ubuntu

    local footstep 64 ubuntu ifconfig docker0 flags 61 4163 lt UP BROADCAST RUNNING MULTICAST gt mtu 1500 inet 172 17 0 1 ne
  • MSCKF学习记录

    MSCKF相关资料 1 github参考实现 xff1a daniilidis group msckf mono https github com daniilidis group msckf mono 2 CSND参考博客 xff1a m
  • ARM linux 串口接收

    C语言read函数的使用以及串口初始化的调用 废话不多说 xff0c 直接上代码 xff0c 有疑问可以看我之前的文章 https blog csdn net m0 38053897 article details 108816643 ht
  • 设计模式--状态模式(C语言实现)

    原创 亚索老哥 embed linux share 模式动机 状态模式 状态机 是嵌入式开发中最重要 最核心的设计模式之一 xff0c 毫不夸张的说 xff0c 是否熟练掌握状态模式 xff0c 很大程度上直接决定了嵌入式工程师的代码掌控能
  • 张正友相机标定 及 一文讲透鱼眼相机畸变矫正,及目标检测项目应用

    参考链接 xff1a 相机标定 张正友标定法 一文讲透鱼眼相机畸变矫正 xff0c 及目标检测项目应用
  • select在ios中选项空白

    出现这个问题是因为粗心吧 解决了好久 最后发现是个笑话 lt select name 61 span class hljs string 34 34 span id 61 span class hljs string 34 34 span
  • RTOS中消息、信号量、互斥量、事件使用区别(类比理解)

    RTOS中消息 信号量 互斥量 事件使用区别 xff08 类比理解 xff09 注 xff1a 本文仅代表本人学习中的理解 xff0c 未必正确 xff0c 欢迎指正 xff01 1 消息 1 1 对FreeRTOS 就像往火车上装货卸货
  • PuTTY/Xshell连接远程服务器提示connection time out的解决方案

    刚注册一台云服务器时 xff0c 想使用PuTTY Xshell来在本地远程连接服务器 xff0c 发现会出现以下错误提示 xff1a Network error Connection time out 对于新注册的云服务器 xff0c 什
  • Ubuntu编译环境配置

    1 升级gcc sudo apt get update sudo apt get install software properties common sudo apt get install gcc 5 g 43 5 sudo apt g
  • 多传感器融合的四种经典结构

    人一生的成长过程中 xff0c 也不总是只有一种必然性 xff0c 很多时候 xff0c 人生需要选择 请选择有尊严的活着 xff0c 告别卑微 xff01 转一篇信息融合的结构概述 xff1a 多传感器信息融合的结构模型一般有四种基本形式
  • 认识Make、Makefile、CMake和CMakeLists

    一 Make 在 认识编译器和C C 43 43 编译 一文中介绍过 xff0c 一个 c cpp 文件从源文件到目标文件的过程叫做编译 xff0c 但是一个项目中不可能只存在一个文件 xff0c 这就涉及到多个文件的编译问题 xff0c
  • 卡尔曼滤波基础---MATLAB

    Karl Gauss xff08 1795年 xff09 行星轨道测量 最小二乘估计法 Norbert Wiener xff08 1942年 xff09 火力控制系统精确跟踪 Wiener Kolmogorov滤波 Rudolf Kalma

随机推荐

  • 位姿估计 -- PPF算法的OpenCV实现

    给出cpp代码 xff0c 复制粘贴改一下文件路径记得 1 pose cpp span class token comment span span class token comment Created by yaohua on 2020
  • 针对ROS配置VScode开发环境(catkin_make 或 catkin build)

    针对ROS配置VScode开发环境 xff08 catkin make 或 catkin build xff09 使用catkin make ubuntu 18的vscode配置ros开发环境 xff1a catkin make span
  • 电脑双系统即在windows系统与Linux系统中如何设置默认启动系统

    来源 xff08 https www bilibili com read cv5277001 xff09
  • Ubuntu添加/删除PPA源

    一 PPA介绍 PPA xff08 Personal Package Archives xff0c 个人软件包文档 xff09 xff0c 是Ubuntu Launchpad网站提供的一项源服务 xff0c 允许个人用户上传软件源代码 xf
  • 操作系统之进程概念及其组成

    一 进程 在多道程序环境下 xff0c 允许多个程序并发执行 xff0c 此时它们将失去封闭性 xff0c 并具有间断性及不可 再现性的特征 为此引入了进程 Prnccss 的概念 xff0c 以便更好地描述和控制程序的并发执行 xff0c
  • GTSAM中imu预积分及其因子图优化过程

    前言 使用IMU和llidar或者相机进行多传感器融合的slam方案中 xff0c 主要分为紧耦合和松耦合方案 目前 xff0c 主流的方案都是紧耦合的 而紧耦合方案中主要分为基于滤波 xff08 比如 xff0c ESKF xff09 和
  • Python 学习笔记 模块 & 目录遍历 & 包

    一 模块 xff1a 1 概述 xff1a 为了解决维护问题 xff0c 一般情况下 xff0c 在一个完整的项目中 xff0c 会将特定的功能分组 xff0c 分别放到不同的文件中 xff0c 在使用的过程中 xff0c 可以单独维护 x
  • realsense-ros环境配置

    项目场景 xff1a 相机型号RealsenseD435i 环境 xff1a ubuntu1604 xff0c 内核4 15 0 126 generic uname r可查看内核 参考链接 xff1a https github com In
  • realsense相机SDK——librealsense使用方法及bug解决(ubuntu)

    realsense环境配置参考https blog csdn net m0 43436602 article details 110930512 一 librealsense在哪里 xff1f 安装完环境之后 xff0c 可以去根目录下搜一
  • uCOS消息队列相关函数的理解

    OSQCreate xff1a 创建消息队列函数 有四个入口参数 xff1a 消息队列指针 xff1b 消息队列名称 xff1b 消息队列大小 xff08 不能为0 xff09 xff1b 返回错误类型 函数过程 xff1a 首先进行安全检
  • uCOS任务信号量相关函数代码理解

    强调任务信号量思想 xff1a 任务信号量只是一个标志 xff0c 获取成功就是指把信号量计数值减1 xff1b 释放就是指把信号量计数值加1 xff08 溢出则计数值不变 xff09 获取信号量需要判断信号量是否可用 xff08 大于0
  • (二)灰度图像二值化

    灰度图像二值化 一 知识简介 图像二值化 xff08 Image Binarization xff09 就是将图像上的像素点的灰度值设置为0或255 xff0c 也就是将整个图像呈现出明显的黑白效果的过程 在数字图像处理中 xff0c 二值
  • Modbus RS485 设备的串口调试

    Modbus RS485 设备的串口调试 准备Modbus功能码二 使用步骤1 接线2 串口调试 温湿度的计算 准备 硬件设备 xff1a 电脑 RS485 温湿度传感器 RS485 土壤温湿度传感器 RS485 继电器控制模块 TTL转R
  • Linux为什么区分内核空间和用户空间

    程序如果要被CPU执行 xff0c 就得编译成CPU可以执行的指令 xff0c 一大堆的程序就变成了一堆的指令 一个操作系统它也是一堆程序组成的 xff0c 可以想象CPU的指令是很多的 xff0c 但是这么多的指令中 xff0c 有些指令
  • 【Docker】镜像的保存(save)到文件 与 加载(load)到宿主机

    背景 xff1a 我们制作好的镜像会存储在宿主机上 xff0c 那么在迁移的过程中 xff0c 我们应该如何 保存自定义的镜像到宿文件 或 加载自定义的镜像到宿主机呢 xff1f 制作镜像 xff1a docker build t 镜像名
  • 手把手教你学会闭包

    前言 MDN对闭包的解释是这样的 xff1a 一个函数和对其周围状态 xff08 lexical environment xff0c 词法环境 xff09 的引用捆绑在一起 xff08 或者说函数被引用包围 xff09 xff0c 这样的组
  • 从高考到程序员:选择专业三要素:擅长、喜欢、有价值

    参与从高考到程序员征文 xff1a http blog csdn net blogdevteam article details 72917467 从高考到程序员 xff1a 选择专业三要素 xff1a 擅长 喜欢 有价值 选择工作三要素
  • 舍选抽样法

    对于一个随机变量X xff0c 对其直接进行抽样比较困难时 xff0c 我们可以选择一个比较容易产生随机数且逼近f很好的一个分布f y 来对其进行抽样 xff0c 下面以贝塔分布为例进行舍选抽样 ps 实际上 应该是先找了一个f y 使得c
  • 初识STM32工作原理和基础编程

    一 初识STM32如何简单的点亮一个LED灯呢 xff1f 如何用一个按键控制LED灯的点亮与否呢 xff1f 本文将对这些问题做一个比较详细的解答 xff0c 其中还有几个比较经典的例子 xff0c 希望能帮助大家更好的理解STM32的工
  • 结构体为何要进行对齐以及如何对齐

    先说如何对齐 xff0c 再讲讲其背后的原理 对齐规则在网上和书上都很容易找到 无非就是以下几点 规则 1 第一个成员在与结构体变量偏移量为0的地址处 2 其他成员变量要对齐到某个数字 xff08 对齐数 xff09 的整数倍的地址处 对齐