当前位置: 首页 > news >正文

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

目录

发现问题

 偏移量宏:offsetof()

结构体内存的对齐规则

小结 


发现问题

有以下两个结构体:

结构体1:

struct S1
{char c1; // 1字节int i; // 4字节char c2; // 1字节
};

结构体2:

struct S2
{char c1; // 1字节char c2; // 1字节int i; // 4字节
};

通常情况下:结构体1的大小是6字节(char是1字节 + int是4字节 + char是1字节);结构体2的大小是6字节(char是1字节 + char是1字节 + int是4字节)

打印结构验真假:

打印发现 结构体1 和 结构体2 所占内存空间的大小并不一样,出现这种结果的原因是因为结构体内存对齐规则的原因,利用宏 offsetof() 可以帮助判断


 偏移量宏:offsetof()

offsetof()  这个宏可以计算结构体成员相较于结构体起始位置的偏移量

头文件为:#include<stddef.h>

计算结构体所有成员对于结构体起始位置的偏移量: 

struct S1
{char c1;int i;char c2;
};
int main()
{printf("%d", offsetof(struct S1, c1));printf("%d", offsetof(struct S1, i));printf("%d", offsetof(struct S1, c2));return 0;
}

计算结果:

可以发现,c1 是char类型的变量,所占内存空间只有1个字节,且是第一个变量,所以放在结构体起始位置偏移量为0的地方,那为什么第二个变量要放在离起始位置偏移量4的地方,中间的3个字节为什么要浪费掉?

由以上问题分析得出,结构体成员不是按照顺序在内存中连续存放的,是有一定的对齐规则


结构体内存的对齐规则

1. 结构体的第一个成员永远放在相较于结构体起始位置的偏移量为0的位置

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

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

对齐数:结构体成员自身的大小和默认对齐数的较小值

默认对齐数:VS编译器上的默认对齐数是8,而gcc这种编译器没有默认对齐数,对齐数就是结构体成员的自身大小 

由以上的规则,我们可以得知,为什么第二个变量要放在相较于结构体起始位置的偏移量为4的位置了

再次复盘以上结构体:

struct S1
{char c1;int i;char c2;
};

第一个成员:char类型的c1变量,放在相较于结构体起始位置的偏移量为0的位置

第二个成员:int类型的i变量,i的大小是4个字节,VS中默认对齐数是8,在4和8中取较小值,也就是4,所以第二个成员变量 i 要放在偏移量为4的倍数处,所以成员变量 i 的偏移量是 4

第三个成员:char类型的c2变量,c2 的大小是1个字节,在1和8中取较小值,也就是1,所以第三个成员变量 c2 要存放在偏移量为1的倍数处,且偏移量为4、5、6、7的位置已经被第二个成员所占,所以 c2 存放在偏移量为8的位置

结构体总大小: 

printf("%d\n", sizeof(struct S1));

结构体的总大小是最大对齐数的整数倍,由以上第二个成员可得出,最大对齐数是4,所以结构体的总大小必须是4的倍数,而当前结构体的大小是9,因为第三个成员是放在偏移量为8的位置的,且占一个字节,所以一共占了9个字节,9不是4的倍数,所以最4的最小整数倍是12,所以最后整个结构体的总大小是12个字节


小结 

除了结构体的第一个成员是放在结构体的起始处位置(也就是相较于结构体起始位置偏移量为0的位置),其他的成员要按照对齐规则存放

且结构体的总大小是结构体成员最大对齐数的整数倍

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 记一次CSDN认证模块后端未校验漏洞
  • 选择IT服务管理,ITIL®和ITSS该如何取舍?
  • Windows 利用compact /EXE:LZX命令 压缩可执行文件 节约空间
  • 千兆以太网
  • 售后服务认证的价值:权威认证带来的全方位优势
  • C++ | Leetcode C++题解之第336题回文对
  • ElasticSearch文档数据关联关系处理
  • HttpUtils工具类(二)Apache HttpClient 5 使用详细教程
  • 英文域名注册选什么样的好?
  • 快讯 | 苹果拟于2026年推出1000美元桌面机器人,集成Siri智能技术
  • JavaScript学习笔记(十三):网络请求JS AJAX
  • 学习嵌入式第二十六天
  • 财务会计与管理会计(七)
  • redis面试(十三)公平锁排队代码剖析
  • 私域场景中的数字化营销秘诀
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • Git 使用集
  • HTTP请求重发
  • Java 多线程编程之:notify 和 wait 用法
  • Laravel 中的一个后期静态绑定
  • mysql 5.6 原生Online DDL解析
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • Spring Cloud中负载均衡器概览
  • WordPress 获取当前文章下的所有附件/获取指定ID文章的附件(图片、文件、视频)...
  • 前端存储 - localStorage
  • 探索 JS 中的模块化
  • 王永庆:技术创新改变教育未来
  • 学习HTTP相关知识笔记
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • 硬币翻转问题,区间操作
  • 在Docker Swarm上部署Apache Storm:第1部分
  • 正则表达式小结
  • 如何在招聘中考核.NET架构师
  • 数据可视化之下发图实践
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • ‌‌雅诗兰黛、‌‌兰蔻等美妆大品牌的营销策略是什么?
  • # wps必须要登录激活才能使用吗?
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • #Datawhale X 李宏毅苹果书 AI夏令营#3.13.2局部极小值与鞍点批量和动量
  • $GOPATH/go.mod exists but should not goland
  • (1)Android开发优化---------UI优化
  • (145)光线追踪距离场柔和阴影
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
  • (补充)IDEA项目结构
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (论文阅读11/100)Fast R-CNN
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)utf8mb4_general_ci 和 utf8mb4_unicode_ci 适用排序和比较规则场景
  • (转)甲方乙方——赵民谈找工作