热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

直击热门考点——结构体内存对齐

原标题:直击热门考点——结构体内存对齐文章目录前言一、引例

原标题:直击热门考点——结构体内存对齐


文章目录



  • 前言

  • 一、引例

  • 二、小试牛刀

  • 三、嵌套结构体的特殊情况

  • 四、关于为什么存在内存对齐

  • 总结






前言

在掌握基本的结构体使用后,我们在面试和大型比赛中常常会遇到一个热门考点:结构体内存对齐,也就是计算结构体大小。接下来请跟着笔者一起来学习这块知识点吧!


提示:以下是本篇文章正文内容,下面案例可供参考


一、引例

到底什么是结构体内存对齐,我们用一段代码来介绍一下

struct S1
{
char c1;//1字节
int a;//4字节
char c2;//1字节
};
int main()
{
printf("%d\n", sizeof(struct S1));
//这里打印12
}

先来解释S1,结构体S1中有2个char类型,1个int类型。那按道理应该是占2*1+4=6个字节啊,为什么打印的是12呢?到这里,我们必须要来了解一下结构体内存对齐的规则:
1.结构体的第一个成员永远放在结构体起始位置偏移量为0的位置
对于偏移量你可以这样理解:数组下标为0的相对它自己偏移量为0,下标为1的相对下标为0的偏移量为1…
举例说明:
在这里插入图片描述
S1第一个成员是c1,它会被放在结构体起始位置偏移量为0的位置,如下图红色部分www.yii666.com
在这里插入图片描述

2.从第二个成员开始,总是放在偏移量为一个对齐数的整数处,对齐数=编译器默认的对齐数和变量自身大小的较小值
对齐数=min(编译器默认的对齐数,变量自身大小)
Linux-没有对齐数,VS下对齐数默认为8

我们仍以S1这个结构体进行举例,结构体第二个成员是int类型的a,占4个字节,笔者VS环境下默认对齐数是8,取两者较小值是4,那a应该放到偏移量为4的倍数上
在这里插入图片描述
放到4的倍数上也就说可以放在偏移量为4这里,偏移量为1,2,3的这3个空间就白白被浪费了。而a是int型占4个字节,所以会一直占用到偏移量为7的位置。

接下来是结构体的第三个成员,char类型的c2,c2占1个字节,VS环境下默认对齐数是8,取较小值为1,也就是说只要是1的倍数的偏移量都可以放,我们紧接着放在a后面,也就是偏移量8的位置
在这里插入图片描述
那到这里结构体3个成员都用完了啊,只有8个啊,为什么打印是12呢?这里就要涉及结构体内存对齐的第3个规则
3.结构体的总大小必须是各个成员的对齐数中最大的那个对齐数的整数倍
我们由前面讲解知道结构www.yii666.com体三个成员c1,a,c2对齐数分别为1,4,1这三个中最大对齐数是4,总大小要为4的整数倍,那这时候肯定有小伙伴会问:我们现在不是对齐到8了嘛,8不是4的倍数吗?注意!这里说的是空间总大小,而8是所谓的偏移量,偏移量是从0开始算的,到8已经有9个空间了,所以我们这里空间要到12,也就是偏移量到11
在这里插入图片描述
(后面加上的三个空间用不到,但是由于规定还是算在结构体总空间内)


二、小试牛刀

我们再来看一道类似的题目

代码如下(示例):

struct S2
{
char c1;//1字节
char c2;//1字节
int a;//4字节
};
int main()
{
printf("%d\n", sizeof(struct S2));
//这里打印8
}

首先第一个结构体成员是char类型的c1,由规则1,它会直接被放在偏移量为0的位置
(图示灰色部分)
在这里插入图片描述
第二个成员是char类型的c2,占1字节,VS下默认对齐数是8,取较小值是1,只要放在偏移量为1的倍数上即可(任意位置),紧跟着0,放在偏移量为1处(图示红色部分)
在这里插入图片描述
最后一个成员int类型的a,占4个字节,VS环境下默认对齐数是8,取较小者4,放在偏移量为4的整数倍处,也就是4这里,然后由于int占4个字节所以一直占用到偏移量7处
在这里插入图片描述
再来看看规则3,结构体的总大小必须是各个成员的对齐数中最大的那个对齐数的整数倍,也就是4的倍数,我们现在正好是占8个空间,8正好是4的倍数,所以就不用再往下浪费空间了,打印出8


三、嵌套结构体的特殊情况

代码如下(示例):

struct S3
{
double d;//double占8字节,默认对齐数8,取较小值,对齐数8
char c;//对齐数1
int i;//对齐数4
};
struct S4
{
char c1;
struct S3 s3;
double d;
};
int main()
{
printf("%d\n", sizeof(struct S4));
}

关于结构体S3我们可以采用和前面S1、S2一样的方法计算出来是占16个字节空间文章来源地址52698.html,我们这里重点讨论S4,对S3有兴趣的小伙伴可自行求解。

S4中的第一个成员c1,按规则1直接放在偏移量为0处,第二个成员s3怎么办呢?这里涉及结构体内存对齐的第四个规则:
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍数处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

s3这个结构体三个成员最大对齐数是8,也就是要对齐到偏移量为8的倍数处,然后s3是占16个字节,所以一直占到偏移量23处(s3结构体对齐数是本身s3结构体三个成员中最大对齐数)

ps:在VS环境中,嵌套结构体的最大对齐数超过8,仍然用8做最大对齐数(比默认对齐数大了,取较小值就取默认对齐数了)
在这里插入图片描述
S4最后一个成员double类型的d占8字节,默认对齐数8,对齐数取8,然后放在偏移量为对齐数的整数倍处,正好往下放在24处,本身占8字节所以占到31
在这里插入图片描述
偏移量0-31共占32字节,S4中的成员c1,s3,d对齐数分别为1,8,8所以最大对齐数是8,32恰是8的倍数,所以这里不用再浪费空间来满足 “结构体的总大小必须是各个成员的对齐数中最大的那个对齐数的整数倍”这个规则,结构体总大小就是32


四、关于为什么存在内存对齐

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




总结

本文介绍了结构体内存对齐的四大规则,并举例说明了如何进行方法的操作,对于其中特殊的嵌套结构体内存对齐也进行了相应讲解,希望读者在学习完本文后能文章来源地址52698.html对结构体内存对齐有一个系统的认文章来源站点https://www.yii666.com/识。祝读者学业有成!

来源于:直击热门考点——结构体内存对齐


推荐阅读
  • 本题来自WC2014,题目编号为BZOJ3435、洛谷P3920和UOJ55。该问题描述了一棵不断生长的带权树及其节点上小精灵之间的友谊关系,要求实时计算每次新增节点后树上所有可能的朋友对数。 ... [详细]
  • 嵌入式开发环境搭建与文件传输指南
    本文详细介绍了如何为嵌入式应用开发搭建必要的软硬件环境,并提供了通过串口和网线两种方式将文件传输到开发板的具体步骤。适合Linux开发初学者参考。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • Linux环境下C语言实现定时向文件写入当前时间
    本文介绍如何在Linux系统中使用C语言编程,实现在每秒钟向指定文件中写入当前时间戳。通过此示例,读者可以了解基本的文件操作、时间处理以及循环控制。 ... [详细]
  • 丽江客栈选择问题
    本文介绍了一道经典的算法题,题目涉及在丽江河边的n家特色客栈中选择住宿方案。两位游客希望住在色调相同的两家客栈,并在晚上选择一家最低消费不超过p元的咖啡店小聚。我们将详细探讨如何计算满足条件的住宿方案总数。 ... [详细]
  • JSOI2010 蔬菜庆典:树结构中的无限大权值问题
    本文探讨了 JSOI2010 的蔬菜庆典问题,主要关注如何处理非根非叶子节点的无限大权值情况。通过分析根节点及其子树的特性,提出了有效的解决方案,并详细解释了算法的实现过程。 ... [详细]
  • 目录一、salt-job管理#job存放数据目录#缓存时间设置#Others二、returns模块配置job数据入库#配置returns返回值信息#mysql安全设置#创建模块相关 ... [详细]
  • 实用正则表达式有哪些
    小编给大家分享一下实用正则表达式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下 ... [详细]
  • 本文介绍如何从字符串中移除大写、小写、特殊、数字和非数字字符,并提供了多种编程语言的实现示例。 ... [详细]
  • Python——简陋的n阶魔方模拟 ... [详细]
  • 使用Python轻松合并大量复杂Excel文件
    当面对大量的Excel文件时,如何高效地将它们合并成一个文件成为了一项挑战。本文将指导初学者如何利用Python的几个库,在几十行代码内完成这一任务。 ... [详细]
  • 本文探讨了如何在Python中处理长数据的完全显示问题,包括numpy数组、pandas DataFrame以及tensor类型的完整输出设置。 ... [详细]
  • 本文介绍 Java 中如何使用 Year 类的 atMonth 方法将年份和月份组合成 YearMonth 对象,并提供代码示例。 ... [详细]
  • CSS高级技巧:动态高亮当前页面导航
    本文介绍了如何使用CSS实现网站导航栏中当前页面的高亮显示,提升用户体验。通过为每个页面的body元素添加特定ID,并结合导航项的类名,可以轻松实现这一功能。 ... [详细]
  • 探讨了在使用Layui框架时,如何处理表格中固定列与其他列行高不一致的情况,提供了有效的解决方案。 ... [详细]
author-avatar
U友50082089
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有