C语言中结构体的内存对齐

【C语言】——结构体进阶:结构体的内存对齐(超详细) 关于结构体,你想知道的都在这里!!! 超详细版本!!! 阅读详情

在开始介绍之前我们先来看一串代码

#include<stdio.h>
struct s1
{
	char a1;//1字节
	int i;//4字节
	char a2;//1字节
};
struct s2
{
	char a1;//1
	char a2;//1
	int i;//4
};
int main()
{
	printf("%d\n", sizeof(struct s1));
	printf("%d\n", sizeof(struct s2));
	return 0;
}

sizeof操作符求内存大小正常来说都是6字节

真正的运行结果↓

一个12 一个8 结果不一样甚至都没有我们预期的6 这里就要说到结构体独特的存储方式(内存对齐)

结构体的内存对齐遵循以下规则↓

1.结构体的第一个成员,对齐到结构体在内存中存放位置的0偏移处

2.从第二个开始,每个成员都要对齐到(一个对齐数)的整数倍处。 对齐数:结构体成员自身的大小和默认对齐数的较小值。VS环境下默认的是8。Linux gcc环境下没有默认对齐数,对齐数就是数据结构体成员的自身大小

3.结构体的总大小,必须是所有成员对齐数中最大对齐数的整数倍

4.如果结构体中嵌套了结构体成员,要将嵌套的结构体成员对齐到自己的成员中最大的对齐数的整数倍处。

注:结构体的总大小必须是最大对齐数的整数倍,最大对齐数就是包含嵌套结构体成员中的对齐数的所有对齐数的最大值

刚看可能有一点蒙圈 根据这些来理解最开始的代码

根据存储规则来解释一下s1 为什么是12字节  

注:上图右侧每一个空格代表一个字节大小

结构体第一个成员char a1存放在内存的0偏移处大小1字节也就是红色的格子

第二个成员int i 并不是从1开始存储 而是从4开始也就是灰色的地方(4字节小于默认值8字节取最小值4为对齐数) 这里就要参考第二条规则 对齐到对齐数4的整数倍处也就是4的位置

黑色代表空间被浪费了(有意义的浪费后面会讲到)

再存储第三个成员char a2, a2是1个字节的大小默认值是8 取最小值1为对齐数 下一个存储位置是8而8是对齐数1的整数倍所以从8开始存储a2占一个字节

最后一步参考第三条结构体的总大小是结构体成员最大对齐数的整数倍,s1的最大对齐数也就是int(4字节) 存储完a2也就是从0-8一共九个字节的大小 不是4的整数倍就要继续占用内存直至到11(0-11)12字节的大小是最大对齐数4的倍数

下面三个字节空间(黑色)被浪费掉了

结构体经过内存对齐之后的大小就是12字节

对于struct s2的大小为什么是8大家可以根据结构体的内存对齐规则和struct s1的案例也可以正确的画出内存存储的就构图来

***对于第四条规则的结构体嵌套 我们给出struct s3 里面嵌套了struct s1

#include<stdio.h>
struct s1
{
	char a1;//1字节
	int i;//4字节
	char a2;//1字节
};
struct s2
{
	char a1;//1
	char a2;//1
	int i;//4
};
struct s3
{
	char a;//1
	struct s1;//12
	double b;//8
};
int main()
{
	printf("%d\n", sizeof(struct s1));//12
	printf("%d\n", sizeof(struct s2));//8
	printf("%d\n", sizeof(struct s3));//24
	return 0;
}

struct s3的大小是24 接下来给出解释

在了解上图的基础上 根据这个图应该很容易就能理解 对于嵌套的struct s1如何存储 我们已知struct s1结构体成员最大对齐数是4 所以从4的位置开始存储(前面三个字节空间浪费掉)struct  s1(由前面求得大小12字节) 直至存够12个字节(4-15)

double 类型大小8字节从16开始存储正好是8的倍数从,存储够8字节(16-23)

最后总大小是最大对齐数的整数倍包括嵌套的结构体里面的 最大的也就是double(8) ,24(0-23)也就是8的整数倍符合规则所以struct s3所占的内存空间大小就是24字节

对于为什么结构体存储要有内存对齐这种规则 这不是浪费内存空间吗?

其实主要有两点原因:

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

2.性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。对于未对齐的内存 处理器需要操作两次内存访问,而对齐的内存访问仅仅需要一次访问。

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

最后补充一点在VS中的默认对齐值是可以修改的 需要一个宏#pragma pack()

#include<stdio.h>
#pragma pack(1)
struct s1
{
	char a1;//1字节
	int i;//4字节
	char a2;//1字节
};
struct s2
{
	char a1;//1
	char a2;//1
	int i;//4
};
int main()
{
	printf("%d\n", sizeof(struct s1));//12(原)
	printf("%d\n", sizeof(struct s2));//8(原)
	return 0;
}

来看看默认对齐值改成1  结构体所占内存大小会如何变化↓.

结果都变了 可以试着自己画图理解

想要恢复哪个结构体的默认值就在哪个结构体前面加上#pragma pack()口号内不要加东西

例如恢复struct s2就在其卡面加 

#include<stdio.h>
#pragma pack(1)
struct s1
{
	char a1;//1字节
	int i;//4字节
	char a2;//1字节
};
#pragma pack()//括号内不要填东西
struct s2
{
	char a1;//1
	char a2;//1
	int i;//4
};
int main()
{
	printf("%d\n", sizeof(struct s1));//12(原)
	printf("%d\n", sizeof(struct s2));//8(原)
	return 0;
}

看一下结果

可以看到struct s2恢复了

 

详解结构体内存对齐 本文详解了结构体内存对齐,具体包括结构体内存对齐的规则、offsetof 宏的介绍和模拟实现、结构体内存对齐的原因以及如何修改默认对齐数。 阅读详情

相关推荐

C语言结构体对齐,超详细,超易懂

结构体对齐规则 结构体的第一个成员总是存放在结构体变量开辟的空间的起始地址 其它成员变量要存储在一个名叫对齐数的整数倍的地址 结构体总大小为最大对齐数的整数倍,结构体内每一个变量都会产生一个对齐数,取其最大的对齐数 如果是嵌套结构体,那么嵌套的结构体存储在嵌套结构体的成员的最大对齐数的整数倍地址处,包含嵌套结构体的结构体大小为自己成员的对齐数和嵌套结构体的成员的对齐数的最大对齐数的整数倍

weixin_54076783的博客 1万+

结构体内存对齐

★★★★★★互相学习,共同进步! 1、结构体内存对齐是指当我们创建一个结构体变量时,会向内存申请所需的空间,用来存储结构体成员的内容。我们可以将其理解为结构体成员会按照特定的规则来存储数据内容。 2、结构体的对齐规则 (1)第一个成员在相比于结构体变量存储起始位置偏移量为0的地址处。 (2)从第二个成员开始,在其自身对齐数的整数倍开始存储(对齐数=编译器默认对齐数和成员字节大小的最小值,VS编译器默认对齐数为8)。 (3)结构体变量所用总空间大小是成员中最大对齐数的整数倍。 (4)当遇到嵌套结构

xxtzzxx的博客 6102

C语言——结构体内存对齐规则

C语言结构体内存对齐规则: 1. 第一个成员在与结构体变量偏移量为0的地址处。 2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。 4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。 附1: 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8 接下来楼主用一些例子来帮助大家理解结构体对齐规则(注:楼..

weixin_53811859的博客 7410

结构体之内存对齐

关于结构体(例如:内存对齐)、位段、枚举、联合等一些知识点的整理。

qq_45283185的博客 3168

【C语言】结构体内存对齐

本文探讨了C语言中结构体和枚举的内存对齐与使用规范。在结构体部分,详细分析了内存对齐规则:成员按对齐数(编译器默认对齐数与成员大小的较小值)的整数倍地址存放,结构体总大小为最大对齐数的整数倍。通过多个示例演示了不同排列方式对内存占用的影响(如S1占12字节而S2仅8字节),指出内存对齐以空间换时间的本质。结构体传参建议传递地址而非整个结构体以避免性能损耗。 位段部分介绍了通过冒号指定成员比特位数的语法特性,但其存在跨平台兼容性问题。枚举类型相比#define具有类型检查优势,默认从0开始递增赋值

小白要加油的博客 1824

C语言-结构体内存对齐

结构体内存如何对齐? 为什么存在内存对齐 ? offsetof - 宏

linkang007的博客 1257

C语言深度理解之——结构体内存对齐

C语言深层理解之结构体在内存中的存储方式

2301_80220607的博客 2115

C语言结构体内存对齐(计算结构体内存大小)

C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础,但一不小心就会弄错。写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这是怎么回事呢? 开始学的时候,也被此类问题困扰很久。其实相关的文章很多,感觉说清楚的不多。结构体到底怎样对齐? 对齐原则方法一有人给对齐原则做过总结,具体在哪里看到现在已记不起来,这里

win_turn的博客 2295

【C语言】_结构体的内存对齐

charc1;inti;charc2;测试其大小:内存分布如下:charc1;charc2;inti;

m0_63299495的博客 999

超详细Tokenizer——文本训练数据预处理

Tokenizer是Keras库中的一个文本处理工具,它用于将文本分词并构建词汇表,同时将文本映射到整数序列。这对于自然语言处理任务非常有用,例如文本分类、情感分析、机器翻译等。

halo的博客 3701

DSP28335与Vofa+上位机通信实战:SCIb配置避坑指南(附完整代码)

本文提供DSP28335与Vofa+上位机通信的实战指南,重点解析SCIb模块配置的常见问题与解决方案。针对研旭开发板的硬件连接、波特率精确计算、FIFO高效使用以及FireWater协议封装进行了详细说明,并附有完整代码,帮助开发者快速实现实时数据可视化与波形分析,提升调试效率。

weixin_29172963的博客 150

【C 语言入门】结构体的内存对齐

结构体是一组不同类型变量的集合,这些变量叫成员变量。比如我们要描述一个学生,包含名字、年龄、性别、学号,用单个变量存太零散,结构体就能完美封装。结构体是不同类型的集合,声明结尾必须有分号。初始化支持顺序和指定成员两种方式。成员访问:变量用点,指针用箭头->。内存对齐:按规则算大小,小成员集中放更省空间。传参优先传地址,效率更高。位段省空间,但跨平台差。

wuqingyigexiaoba的博客 845

Ansys Lumerical 启动时出现 Error: Could not connect to Ansys license server specified at 1055@ 的一种解决办法

考虑到 2020 版的时候是直接在全局变量里指定具体地址,但是 2024 版本是写成 1055@localhost ,并且之后在站里搜相关 Ansys 的问题都指向 1055 端口被占用,虽然问题不一样,但是本着死马当活马医,就按照。我最近在跑超透镜结构,听说2024版本现在有GPU加速可以用,就把Lumerical从2020升到2024版本,结果发现一开头的破解办法完全不一样了。一开始安装的时候以为2020没有删干净,导致2024版的安装一直锁着目标地址,解决办法参考。的办法来操作,在关闭了。

qq_51404184的博客 5753

c语言结构体的内存对齐

结构体的内存对齐是拿空间来换取时间的做法。虽然根据内存对齐可能会开辟不必要的空间,但是为了保障读取数据的速度,拿空间换时间是值得的!其实,在设计结构体的时候,我们的目的是既要满足对齐,又要节省空间,这又如何做到呢?我们可以通过调整成员变量声明的顺序来减少结构体因为内存对齐的空间亏损。int i;char c2;char c2;int i;S1和S2类型的成员一模一样,但是S1和S2所占空间的大小有了一些区别。

稻草人敲代码的博客 486

ADS2023实战:2.4GHz超外差接收机从设计到链路预算全流程解析

本文以ADS 2023软件为平台,详细解析了2.4GHz超外差接收机从核心指标定义、架构原理到完整链路搭建与仿真的全流程。通过实战演练,重点阐述了如何利用ADS进行谐波平衡仿真和链路预算分析,以量化评估系统增益、噪声系数等关键性能,为射频工程师提供了一套从理论到仿真的系统级设计方法。

herb5的博客 817

mapbox进阶,dem数据转为等高面,加载转换后的等高面到地图

本文详细介绍如何基于mapbox-gl v3.*.* 版本,使用dem数据转为等高面,加载转换后的等高面到地图,亲测可用。希望能帮助到您。一起学习,加油!加油!

我哎GIS博客 407

C语言结构体及内存对齐

struct 结构体名 {数据类型 成员名1;数据类型 成员名2;// 可以有多个不同类型的成员数据类型 成员名n;int age;内存对齐是空间换时间的设计,让 CPU 访问更高效。计算大小需遵循“成员对齐”和“整体对齐”规则。可通过强制修改对齐数。成员对齐看自身,整体对齐看最大,可强制。

liutianyuan__的博客 892

Transformer-LSTM预测 | 基于Transformer-LSTM的多变量单步时间序列预测(Matlab)

Transformer-LSTM预测 | 基于Transformer-LSTM的多变量单步时间序列预测(Matlab)

机器学习之心的博客,关注并私信文章链接,获取对应文章源码和数据。 192

【C语言进阶】内存函数和结构体内存对齐

在之前我们学习过strcpy和strncpy函数,他们是专门针对字符串拷贝的函数。而其他类型则不能使用,为了能够拷贝多种数据类型,C语言有这样的内存函数memcpy,memcpy函数则是以字节为单位拷贝数据。函数memcpy从src的位置开始向后复制count个字节的数据到dest的内存位置.这个函数在遇到 ‘\0’ 的时候并不会停下来。因为不是字符串函数如果dest和src有任何的重叠,则可能会出现错误。函数原型注意事项和memcpy的差别就是memmove函数处理的。

喜欢就坚持吧 1412

WindowsServer2022蓝牙音频开启方法

为Windowsserver 2022 添加蓝牙音频驱动的方法和工具

thebestismin的专栏 2705

OSCP-1-3-natraj(本地文件包含、日志中毒、apache2配置漏洞、nmap提权)

像往常一样,我们将使用“Netdiscover”工具识别主机的 IP。所以,让我们首先用 nmap 列出所有 TCP 端口。我们从访问web服务(80端口)开始,在那里我们找到了几张关于Natraj的图片和信息,我们将查看源代码和robots.txt,似乎没有什么有用的。(或至少,目前)。因此,让我们继续进行。在 Dirb 及其默认字典的帮助下,我们找到了一个名为“”的目录。我们进入并列出一个名为“”的文件:如果我们执行它,我们会看到它什么也不做。我们可能需要添加其他内容。

墨痕诉清风的博客 529

C语言结构体内存对齐

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar

pigern的博客 589

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

【C语言13】结构体的声明,定义与结构体的内存对齐

一、结构体

南喵的博客 1660

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

C语言中的结构体在内存当中的对齐方式以及对齐原因

C语言中的结构体在内存当中的对齐方式以及对齐原因

2301_80205070的博客 1401

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

c语言结构体的对齐方式,C语言结构体内存的对齐知识详解

前言在前面的章节中,我们谈到了C语言中整数以及浮点数的储存今天,我们来谈一谈一些关于结构体内存的知识。我们先来看一个例子:struct S1{char c1;int i;char c2;};大家来猜猜这个结构体S1的内存是多少?相信会有人给出 6 的结果,他们或许是这样想的,两个 char 类型分别为一个字节,一个 int 类型又为4个字节,加起来刚好为6个但是结果真是如此吗?我们来看看运行结果:...

weixin_29443363的博客 2921
上一篇: C语言中的回调函数 以及应用
下一篇: C语言动态内存管理中malloc,calloc,realloc,free函数介绍
刘 大 望
博客等级 码龄2年 896粉丝 61原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值