结构体中内存的对齐

前言


学C的同学应该知道~

想精通C语言就不得不面对—指针与内存

续上次指针进阶,这一章我来聊一聊C语言内存对齐的问题

学习结构体的你有没有注意过结构体向系统申请的内存为多少呢的😁

思考 

#include<stdio.h>
typedef struct s1
{
    char a;
    char b;
    int c;
}s1;
typedef struct s2
{
    char a;
    int c;
    char b;
}s2;
int main()
{
 
    //内存对齐的现象
    printf("%d\n", sizeof(s1));
    printf("%d\n", sizeof(s2));
    return 0;
}


很显然这一段代码就是计算s1与s2向系统申请的内存大小

我:两个char类型各为一,再加上应该int类型的四,结果就是六

诚挚的乔治:你说的对,但不完全对,在结构体中会出现内存对齐的现象,不信?看结果

别慌,看到文章的最后,你(也许)就会恍然大悟

在结构体中,内存不是成员的大小之和

📃结构体在内存中开辟空间时内存对齐的规则:
1.结构体中的第一个成员存放在这个结构体的零偏移处,故第一个成员char类型的的偏移量为零

2.从第二个成员开始,每个成员都要对齐到成员对齐数的整数倍

对齐数--成员自身大小与默认对齐数的最小值的整数倍,如果自身大小是四,默认对齐数是八,最终的对齐数就是四的倍数),一般情况下默认对齐数就是八。

3.结构体的总大小必须是最大对齐数的整数倍 。

最大对齐数就是每个成员对齐数中的最大值

4.如果结构体中嵌套结构体的情况下,嵌套的结构体就对齐到自己成员对齐数的最大对齐数的整数倍处,结构体的总大小就是最大对齐数(含嵌套的结构体成员)的整数倍。

 下面其中的一个结构体进行分析:

 先向大家介绍一下本章的配角—offsetof

 offsetof的返回值就是距离这个结构体(自定义类型)起始位置的值

参数就是结构体的名称和结构体成员的名称。

#include<stddef.h>
#include<stdio.h>
typedef struct s
{
    char a;
    int b;
    char c;
}s;
int main()
{
    //offsetof-是指偏移量
    printf("%d\n", offsetof(s,a));
    printf("%d\n", offsetof(s,b));
    printf("%d\n", offsetof(s,c));
    return 0;
}

 char a; //因为char a是结构体第一个成员,所以偏移量就是零
  int b;      //自身大小:4    默认对齐数:8   对齐数:4的倍数即可,所以偏移量就是四
 char c;    // 自身大小:1    默认对齐数:8   对齐数:1的倍数即可,所以偏移量就是八

又因为最终的结构体大小是成员最大对齐数的倍数,也就是四的倍数,所以最终的结构体的大小应该就是十二。

 到这里是不是有一定的思路了,别急,再来一道试试吧

#include<stddef.h>
#include<stdio.h>
typedef struct s
{
    double a;
    char b;
    int  c;
}s;
int main()
{
    //offsetof-是指偏移量
    printf("%d\n", offsetof(s,a));
    printf("%d\n", offsetof(s,b));
    printf("%d\n", offsetof(s,c));
    printf("%d", sizeof(s));
    return 0;
}


结果如下:

是不是跟你想的一样呢?

同样的,用一样的方法进行解释

double a;     //因为double a是结构体第一个成员,所以偏移量就是零
    char b;     //自身大小:1    默认对齐数:8   对齐数:1的倍数即可,所以偏移量就是八
    int  c;        //自身大小:4    默认对齐数:8   对齐数:4的倍数即可,所以偏移量就是十二

最终结构体的大小就是四的整数倍十六

下面给应该结构体嵌套结构体的例子

#include<stdio.h>
#include<stddef.h>
typedef struct s1
{
    char i;
    char j;
    int k;
}s1;
typedef struct s2
{
    char a;
    int c;
    s1;
}s2;
int main()
{
 
    printf("%d\n", offsetof(s2, a));
    printf("%d\n", offsetof(s2, c));
    printf("%d", sizeof(s2));
    return 0;
}


 我相信此时的你一定会计算结构体想系统申请的大小,以及内存对齐是咋回事

其实,内存对齐也就那么回事儿~

为什么存在内存对齐


 知道怎样计算后,你是否和我一样思考

为什么内存的申请不能想main函数中的内存申请一样,要多少就申请相应大小的空间,这样既省内存,也不用考虑这么多。

1.平台的原因


所谓平台原因就是与硬件有关,硬件不能访问内存中的每一个空间,换句话说,就是按一定的规律进行访问,这样内存对齐就起到了很好的作用

2.性能的原因


数据结构(尤其是栈),应该尽可能的在自然边界上对齐

因为我们的CPU访问空间,就是一次性按四个字节的空间来访问,内存对齐在一定的时候避免了访问一次的空间进行了二次访问

如下访问应该int类型内存对齐后只需要访问一次

 

总的来说内存对齐就是拿空间换取时间

当然,我们可以实现内存对齐之上,也可以进行省一定空间

就想博客开头一道题,一模一样的代码,最终的结构体的大小却不一样,这种就是优化版的结构体

这里给一个小的技巧,就是把空间小的成员尽量放在一起

欢迎点赞收藏加关注,如若有问题可以提出来😁😁😁😁 

欢迎大家来评论区理性交流、学习,咱们下期见!!
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/663692.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Python】 如何获取 Python 函数的名称作为字符串?

基本原理 在 Python 中&#xff0c;获取函数名称是一个简单但非常有用的技巧&#xff0c;尤其是当你需要动态地引用函数或者在日志、调试中需要函数名称时。Python 提供了几种方法来获取函数的名称。 方法一&#xff1a;使用 __name__ 属性 每个函数对象都有一个 __name__ 属…

【Unity】使用Jenkins实现远程Unity打包

前言 很多时候&#xff0c;我们需要自动打包&#xff0c;比如下班了&#xff0c;我要出一个包明天早上用。比如每天夜里12点&#xff0c;我需要定时出一个稳定包。 这个时候就需要Jenkins了。 1.安装环境 安装 jenkins 之前&#xff0c;需要安装Java 。Java下载网站 ①下载…

校园交友|基于SprinBoot+vue的校园交友网站(源码+数据库+文档)

校园交友网站 目录 基于SprinBootvue的校园交友网站 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2后台功能模块 5.2.1管理员功能模块 5.2.2用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#x…

音视频开发9 FFmpeg 解复用相关整体说明,重要API说明

一&#xff0c;播放器框架 二 常用音视频术语 容器&#xff0f;文件&#xff08;Conainer/File&#xff09;&#xff1a; 即特定格式的多媒体文件&#xff0c; 比如mp4、flv、mkv等。 媒体流&#xff08;Stream&#xff09;&#xff1a; 表示时间轴上的一段连续数据&#xff0…

【技术实操】银河高级服务器操作系统实例分享,数据库日志文件属主不对问题分析

1. 问题现象描述 2023 年 06 月 30 日在迁移数据库过程中&#xff0c;遇到数据库 crash 的缺陷&#xff0c;原因如下&#xff1a;在数据库启动时候生成的一组临时文件中&#xff0c;有 owner 为 root 的文件&#xff0c; 文件权限默认为 640&#xff0c; 当数据库需要使用的时…

C++系列——————类和对象(上)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、面向对象的三大特征二、类的引入2.1类的定义 三.类的访问限定符3.1访问限定符的介绍3.2.访问限定符的使用 四、类的作用域五、类的实例化六、类对象模型6.1…

惠海 H6251L 降压恒压芯片IC 48V 60V 100V 150V 200V 降3.3V 5V 12V 5A大电流 低功耗,动态响应优异

H6251L是一款多样化的高压降压开关控制器&#xff0c;它具备许多引人注目的特性和优势&#xff0c;使其在多个领域都有许多的应用。以下是对H6251L的详细分析&#xff1a; 首先&#xff0c;H6251L具有宽压8V-200V的输入范围&#xff0c;这意味着它可以在电压环境下稳定工作&am…

【康耐视国产案例】智能AI相机联合OSARO为Zenni眼镜实现订单履约自动化

在电商潮流下&#xff0c;Zenni眼镜作为全球领先的在线眼镜零售商&#xff0c;每年销售超过600万副眼镜&#xff0c;却面临着一个独特而复杂的问题——需要通过扫描眼镜盒内的条形码来处理订单。传统手动处理已经到达流程瓶颈&#xff0c;急需一种更加自动化、可扩展的方法。为…

STM32 HAL库USART的接收数据方法实现(STM32Cube_FW_F1_V1.8.5)

目录 概述 1 使用STM32Cube生成项目 1.1 软件版本信息 1.2 配置串口相关参数 1.3 生成工程 2 问题描述 3 解决问题 3.1 修改代码 3.2 编写新的回调函数 4 测试 概述 本文主要介绍STM32 HAL库USART的接收数据方法实现&#xff0c;笔者使用的HAL库为STM32Cube_FW_F1_V1.…

Leetcode刷题笔记6

34. 在排序数组中查找元素的第一个和最后一个位置 34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a;暴力查找 [1, 2, 3, 3, 3, 4, 5] t 3 从前往后扫描暴力查找&#xff0c;最坏情况下O(N) 优化 利用数组有序的…

【动态规划 组合数学 放球问题】2338. 统计理想数组的数目

本文涉及知识点 动态规划汇总 组合数学汇总 【组合数学 隔板法 容斥原理】放球问题 本题同解 【动态规划】【前缀和】【分组】2338. 统计理想数组的数目 LeetCode2338. 统计理想数组的数目 给你两个整数 n 和 maxValue &#xff0c;用于描述一个 理想数组 。 对于下标从 0…

Unity中模拟生成正态分布的一种方式

using System; using System.Collections; using System.Collections.Generic; using Unity.Mathematics; using UnityEngine;public class MathFunction : MonoBehaviour {private void Start(){//key 范围 0-99 表示 0% 到 99%Dictionary<int,uint> m new Dictionary&…

CSS绘制圆弧

css绘制如图的圆弧&#xff1a; 这种矩形弧形的效果中&#xff0c;弧形的效果一般是由一条曲线拉伸出来的&#xff0c;这条曲线往往是属于一个椭圆的&#xff0c;所以可以绘制一个椭圆&#xff0c;截取部分可视区域实现效果。 <style> .wrapper{width: 400px;height: 60…

Hive原理及、部署和以及使用(超详细)

Hive的安装配置、初始化元数据、启动 1、解压hive到指定目录/usr/local/src 改名&#xff0c;将mysql的驱动包拷贝到hive的lib目录下 2、环境变量 1&#xff09; vi /etc/profile export HIVE_HOME/usr/local/src/hive export PATH P A T H : PATH: PATH:HIVE_HOME/bin echo…

20 厂商文档学习资料查询

01 厂商介绍 新华三&#xff08;H3C&#xff09; 新华三是一家专注于IT基础设施产品和解决方案的公司&#xff0c;提供从网络设备到数据中心解决方案的全套服务。它是中国领先的网络解决方案供应商之一&#xff0c;业务涵盖企业网、数据中心、云计算等多个领域。 华为&#x…

Java排序算法汇总篇,八种排序算法

排序算法汇总: Java排序算法(一)&#xff1a;冒泡排序 Java排序算法(二)&#xff1a;选择排序 Java排序算法(三)&#xff1a;插入排序 Java排序算法(四)&#xff1a;快速排序 Java排序算法(五)&#xff1a;归并排序 Java排序算法(六)&#xff1a;希尔排序 Java排序算法(…

科普之旅 | 什么是大语言模型

作者&#xff1a;陈之炎本文约2000字&#xff0c;建议阅读5分钟 本文介绍了大语言模型。 导读 在这个信息爆炸的时代&#xff0c;你是否曾幻想过与机器流畅交谈&#xff0c;或是让AI助你笔下生花&#xff0c;创作出惊艳的文章&#xff1f;这一切&#xff0c;都离不开大语言模型…

港口利器:ModbusTCP转CAN轻松连接,提升跨运车效率!

BXKJ系列嵌入式通信模块&#xff0c;宛如一把神奇的钥匙&#xff0c;打开了与特定工业网络沟通的神秘之门。这些模块的可互换性&#xff0c;赋予了用户自由连接至任何所需网络的无限可能。它们与众多主流现场总线和工业以太网网络无缝对接&#xff0c;包括但不限于Profibus、De…

matlab(实例):滤波器(低通、带通、高通,使用butter函数、filter函数)

一、题目&#xff1a;已知一个时域信号&#xff0c;包含三个频率&#xff08;50Hz、150Hz、300Hz&#xff09;&#xff0c;分别设计并使用低通滤波器、带通滤波器、高通滤波器&#xff0c;对其进行滤波&#xff0c;画出滤波信号的时域图和频谱图。 二、解题过程&#xff1a; ①…

孩子用的灯什么样的好?安利几款适合孩子用的护眼台灯

随着学生们重返校园&#xff0c;家长和孩子们忙于新学期的准备工作&#xff0c;眼睛健康的考量自然也在其中。这也是为何近年来护眼台灯越来越受到欢迎的原因之一。作为一个长期近视并且日常用眼时间较长的人&#xff0c;我本人对护眼台灯有着长期的使用经历&#xff0c;并对它…