如何计算结构体变量的大小(结构体内存对齐)

2024-06-20 17:20

本文主要是介绍如何计算结构体变量的大小(结构体内存对齐),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

   

目录

一、对齐规则

二、结构体大小计算三步曲

第一步:确定对齐数

第二步:根据对齐数确定每个成员相对位置

第三步:通过最大对齐数来确定结构体最终大小

三、内存浪费

四、为什么要存在内存对齐


    在C语言中,变量由于类型不同在内存中开辟空间的大小不同,而结构体类型是一种特殊的变量类型,其可以是多个类型的集合,甚至结构体嵌结构体类型,那么结构体类型变量占内存空间的大小该如何计算呢?这也是一个特别热门的考点。

一、对齐规则

1.结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处。


2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
        对齐数 = 编译器默认的一个对齐数与该成员变量大小的较小值
        VS 中默认的值为 8 
        Linux中gcc没有默认对齐数,对齐数就是成员自身的大小


3.结构体总大小为最大对齐数(结构体中每个成员变量都有⼀个对齐数,所有对齐数中最大的)的
整数倍


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

二、结构体大小计算三步曲

我们由此结构体举例说明(vs环境):

struct S3
{char c;double d;int i;
};

第一步:确定对齐数

找出每个成员变量的大小将其与编译器的默认对齐数相比较,取其较小值为该成员变量的对齐数。

第二步:根据对齐数确定每个成员相对位置

结构体变量地址为零下标,结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处,其他成员变量要对齐到对齐的整数倍的地址处。

第三步:通过最大对齐数来确定结构体最终大小

结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数,所有对齐数中最大的)的
整数倍。

看上图:紫色部分(double d成员占用)+红色部分(char c成员占用)+绿色部分(int i成员占用)+红色与紫色之间的白色部分总共占用了20个字节的内存空间。而20并非最大对齐数8的整数倍,那么取8大于20的最小整数倍24为结构体最终大小。

三、内存浪费

        由于对齐规则的存在,导致结构体虽然成员变量相同,但很可能会出现结构体大小不同的情况造成内存浪费。

        我们可以在构建结构体时,将每个成员变量的间隙在保证符合对齐规则的情况下尽量减小,这是一种合理且推荐使用的方法。

        当然也可以使用#pragma pack( )的预处理来修改默认对齐数以达到减小空隙的效果,但是不推荐。详细见:C语言中#pragma pack(1)的用法_#pack(1)-CSDN博客

#include <stdio.h>#pragma pack(4)//设置默认对齐数为4
struct S1
{double a;//8/4->4int b;//4/4->4char c;//1/4->1
};//12
#pragma pack()//取消设置的默认对齐数,还原为默认#pragma pack(1)//设置默认对齐数为1
struct S2
{char a;//1/1->1int b;//4/1->1char c;//1/1->1
};//6
#pragma pack()//取消设置的默认对齐数,还原为默认int main()
{printf("%d\n", sizeof(struct S1));//打印结果为16printf("%d\n", sizeof(struct S2));//打印结果为6return 0;
}

四、为什么要存在内存对齐

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


2. 性能原因:
        数据结构(尤其是栈)应该尽可能地在自然然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。假设一个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对齐成8的倍数,那么就可以用一个内存操作来读或者写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两个8字节内存块中。


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


 

这篇关于如何计算结构体变量的大小(结构体内存对齐)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

Python+PyQt5实现文件夹结构映射工具

《Python+PyQt5实现文件夹结构映射工具》在日常工作中,我们经常需要对文件夹结构进行复制和备份,本文将带来一款基于PyQt5开发的文件夹结构映射工具,感兴趣的小伙伴可以跟随小编一起学习一下... 目录概述功能亮点展示效果软件使用步骤代码解析1. 主窗口设计(FolderCopyApp)2. 拖拽路径

Java计算经纬度距离的示例代码

《Java计算经纬度距离的示例代码》在Java中计算两个经纬度之间的距离,可以使用多种方法(代码示例均返回米为单位),文中整理了常用的5种方法,感兴趣的小伙伴可以了解一下... 目录1. Haversine公式(中等精度,推荐通用场景)2. 球面余弦定理(简单但精度较低)3. Vincenty公式(高精度,

java变量内存中存储的使用方式

《java变量内存中存储的使用方式》:本文主要介绍java变量内存中存储的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍2、变量的定义3、 变量的类型4、 变量的作用域5、 内存中的存储方式总结1、介绍在 Java 中,变量是用于存储程序中数据

windows和Linux使用命令行计算文件的MD5值

《windows和Linux使用命令行计算文件的MD5值》在Windows和Linux系统中,您可以使用命令行(终端或命令提示符)来计算文件的MD5值,文章介绍了在Windows和Linux/macO... 目录在Windows上:在linux或MACOS上:总结在Windows上:可以使用certuti

Pyserial设置缓冲区大小失败的问题解决

《Pyserial设置缓冲区大小失败的问题解决》本文主要介绍了Pyserial设置缓冲区大小失败的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录问题描述原因分析解决方案问题描述使用set_buffer_size()设置缓冲区大小后,buf

详解C++中类的大小决定因数

《详解C++中类的大小决定因数》类的大小受多个因素影响,主要包括成员变量、对齐方式、继承关系、虚函数表等,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录1. 非静态数据成员示例:2. 数据对齐(Padding)示例:3. 虚函数(vtable 指针)示例:4. 继承普通继承虚继承5.

使用Java实现通用树形结构构建工具类

《使用Java实现通用树形结构构建工具类》这篇文章主要为大家详细介绍了如何使用Java实现通用树形结构构建工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录完整代码一、设计思想与核心功能二、核心实现原理1. 数据结构准备阶段2. 循环依赖检测算法3. 树形结构构建4. 搜索子

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

Python中如何控制小数点精度与对齐方式

《Python中如何控制小数点精度与对齐方式》在Python编程中,数据输出格式化是一个常见的需求,尤其是在涉及到小数点精度和对齐方式时,下面小编就来为大家介绍一下如何在Python中实现这些功能吧... 目录一、控制小数点精度1. 使用 round() 函数2. 使用字符串格式化二、控制对齐方式1. 使用

mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据

《mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据》文章主要介绍了如何从.frm和.ibd文件恢复MySQLInnoDB表结构和数据,需要的朋友可以参... 目录一、恢复表结构二、恢复表数据补充方法一、恢复表结构(从 .frm 文件)方法 1:使用 mysq