首页 > 系统相关 >结构体内存对齐

结构体内存对齐

时间:2024-07-09 21:00:14浏览次数:14  
标签:变量 成员 默认 对齐 结构 体内 字节

计算结构体所占用的内存是在学习C语言时需要学习的内容,学习结构体内存对齐是计算结构体所占空间必不可少的知识点。

那么什么是结构体内存对齐呢?相信学完这篇文章后,你会对结构体有更加深入的理解。

对齐规则

1. 结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处。 2. 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。 对⻬数 = 编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值
  • - VS 中默认的值为 8
  • - Linux中 gcc 没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩
3. 结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的 整数倍。 4. 如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构 体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。

练习

下面让我们通过几个练习来了解上面结构体的对齐规则。

练习1

为了方便计算,我们画了一个图,图中一个格子代表一个字节。

如上图所示,从偏移量为0的位置开始存放,由于结构体中的第一个成员变量是char c1,所以占一个字节,从第二个结构体成员变量开始,内存要对齐到对齐数的整数倍处,由于我们使用的编译器是VS,且VS默认的对齐数是8个字节,且成员变量的对齐数等于编译器的默认对齐数与成员变量所占空间大小的最小值,且第二个成员变量为int类型,占4个字节,所以第二个成员变量的对齐数是4,以此类推,第三个成员变量的对齐数是1,整个结构体的总大小为4的倍数,即结构体总大小为12个字节。

所以输出结果为12个字节,如下图:

练习2

为了方便计算,我们画了一个图,图中一个格子代表一个字节。

如上图所示,从偏移量为0的位置开始存放,由于结构体中的第一个成员变量是double d,所以占8个字节,从第二个结构体成员变量开始,内存要对齐到对齐数的整数倍处,由于我们使用的编译器是VS,且VS默认的对齐数是8个字节,且成员变量的对齐数等于编译器的默认对齐数与成员变量所占空间大小的最小值,且第二个成员变量为char类型,占1个字节,所以第二个成员变量的对齐数是1,以此类推,第三个成员变量的对齐数是4,整个结构体的总大小为8的倍数,即结构体总大小为16个字节。

所以输出结果为16个字节,如下图:

练习3

为了方便计算,我们画了一个图,图中一个格子代表一个字节。

如上图所示,从偏移量为0的位置开始存放,由于结构体中的第一个成员变量是char c1,所以占1个字节,从第二个结构体成员变量开始,内存要对齐到对齐数的整数倍处,由于我们使用的编译器是VS,且VS默认的对齐数是8个字节,且成员变量的对齐数等于编译器的默认对齐数与成员变量所占空间大小的最小值,且第二个成员变量为结构体类型,结构体成员中的最大对齐数占8个字节,所以第二个成员变量的对齐数是8,以此类推,第三个成员变量的对齐数是8,整个结构体的总大小为8的倍数,即结构体总大小为32个字节。

所以输出结果为32个字节,如下图:

修改默认对齐数

其实,在VS编译器中,我们的默认对齐数是可以修改的,只需要用到#pragma 这个预处理指令,可以改变编译器的默认对⻬数。

例如:

从练习1中我们可以知道如果默认对齐数为8时,这个结构体的对齐数为12,如果将默认对齐数修改为1呢?这个结构体的对齐数是否为变为6,答案是肯定的。

输出结果为:

修改默认对齐数的代码为#pragma pack(想要设置的对齐数),需要注意的是,当用完后,需要用代码#pragma pack()取消自己设置的默认对齐数

结构体内存需要对齐的原因

1. 平台原因 (移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 2. 性能原因: 数据结构(尤其是栈)应该尽可能地在⾃然边界上对⻬。原因在于,为了访问未对⻬的内存,处理器需要作两次内存访问;⽽对⻬的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以⽤⼀个内存操作来读或者写值了。否则,我们可能需要执⾏两次内存访问,因为对象可能被分放在两个8字节内存块中。 总体来说:结构体的内存对⻬是拿空间来换取时间的做法。 那么在设计结构体的时候,我们如何做到既节省时间又节省空间呢? 答案是 让占⽤空间⼩的成员尽量集中在⼀起。 例如: 如图所示,可以看到这个例子与练习1基本相同,唯一的不同在于结构体中成员变量的顺序不一样,那么这样做真的可以节省空间吗?答案是肯定的。 如图所示,输出结果为8: 那么输结果为什么是8呢?原因如下图: 从偏移量为0的位置开始存放,由于结构体中的第一个成员变量是char c1,所以占1个字节,从第二个结构体成员变量开始, 内存要对齐到对齐数的整数倍处,由于我们使用的编译器是VS,且 VS默认的对齐数是8个字节,且成员变量的对齐数等于编译器的默认对齐数与成员变量所占空间大小的 最小值,且第二个成员变量为char c2,所以第二个成员变量的对齐数是1,以此类推,第三个成员变量的对齐数是4,整个结构体的总大小为4的倍数,即结构体总大小为8个字节。 所以,在创建结构体的过程中, 将占用空间小的成员尽量集中在一起,可以帮助我们节省存储空间。

标签:变量,成员,默认,对齐,结构,体内,字节
From: https://blog.csdn.net/weixin_71853810/article/details/140303358

相关文章

  • Dotnet算法与数据结构:Hashset, List对比
    哈希集A是存储唯一元素的集合。它通过在内部使用哈希表来实现这一点,该哈希表为基本操作(如添加、删除和包含)提供恒定时间平均复杂度(O(1))。此外,不允许重复元素,使其成为唯一性至关重要的场景的理想选择。另一方面,表示按顺序存储元素的动态数组。它允许重复元素并提供对元素的索引......
  • 小学期数据结构——消球游戏
    消球游戏设计一个程序实现消球游戏:在棋盘内,一开始随机初始化三个不同色小球,一次可移动一个小球至空白位置,当同色5个小球连成直线,横、竖、对角均可,则小球消除并得分。消除1个小球得1分,当小球移动1次没有消除时,系统会自动随机产生三个小球。基本要求:(1)要求实现图形化界面,可......
  • 【数据结构】模块一:线性存储
    数据结构的学习大致可以分为三个模块,分别是:线性结构,非线性结构,查找和排序。首先从线性结构开始学起:线性结构,简单地说,就是把所有的结点用一根直线穿起来。线性结构可以分为连续存储(数组)和离散存储(链表)两种存储方式,共有两种常见的应用,即栈和队列,其二者只不过是简化版的数组......
  • 【模型预测控制】单向拓扑结构下异构车辆排分布式模型预测控制【含Matlab源码 4968期
    ✅博主简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,Matlab项目合作可私信或扫描文章底部QQ二维码。......
  • MySQL 源码|LEX 结构体
    LEX结构体源码位置:(版本=MySQL8.0.37)sql/sql_lex.hsql/sql_lex.ccsql/sql_class.ccrouter/src/routing/src/sql_lexer.ccLEX对象当前有以下功能:包含了一些SQL命令的通用属性,例如:sql_command,数据变更语句语法中是否存在IGNORE,以及表列表query_tables包含了一些......
  • 数据结构第17节 最小堆
    最小堆(MinHeap)是一种特殊的完全二叉树数据结构,在这种结构中,对于任意节点,其值都小于或等于它的子节点的值。根节点是堆中的最小元素。最小堆常用于实现优先队列,以及堆排序算法。在Java中,我们可以使用数组或ArrayList来实现最小堆,因为完全二叉树的特性允许我们通过简单的数......
  • 数据结构第18节 散列表
    散列表(HashTable),也称为哈希表,是一种数据结构,它使用哈希函数将键映射到数组的一个索引位置,从而可以快速地插入、查找和删除数据。散列表的核心在于哈希函数和解决冲突的策略。在Java中,散列表的实现通常涉及以下几个关键部分:哈希函数:用于将键转换为数组索引。解决冲突:多个......
  • Go 中空结构体的用法,我帮你总结全了!
    Go中空结构体的用法,我帮你总结全了!原创 江湖十年 Go编程世界 2024年06月05日07:51 浙江 4人听过在Go语言中,空结构体 struct{} 是一个非常特殊的类型,它不包含任何字段并且不占用任何内存空间。虽然听起来似乎没什么用,但空结构体在Go编程中实际上有着广泛的应......
  • 数据结构——二叉树之c语言实现堆与堆排序
    目录前言:1.二叉树的概念及结构1.1特殊的二叉树 1.2二叉树的存储结构  1.顺序存储2.链式存储 2.二叉树的顺序结构及实现 2.1堆的概念   ​编辑2.2堆的创建3.堆的实现3.1堆的初始化和销毁 初始化:销毁: 插入:向上调整:删除: 向下调整: 堆顶元素......
  • Redis数据类型与实现结构
    Redis提供了多种数据类型,每种数据类型都有其独特的实现结构和使用场景。以下是Redis中常见的数据类型及其底层实现结构:字符串(String)字符串是最基本的数据类型,可以存储二进制安全的字符串、整数或浮点数。实现结构:Redis使用 SDS(SimpleDynamicString)结构来存储字符串,这......