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

结构体内存大小

000、前言

要想计算结构体内存大小,就会涉及到一个结构体内存对齐的问题,而不是对其成员进行简单的加运算

(1)在写本博客之前

有位同学和我讨论了一个学校的题目,题目如下:
在这里插入图片描述
我借这道题目问了另外一位同学,这位同学认为答案为12,理由是这样的

“4(int的大小)+4(y数组的大小)+4(float的大小)=12”

(2)我的思考

老实说,我不太好评价学校的C语言课,但是这道题目如果没有细讲的话,很有可能造成一定程度上的误解。稍微知道结构体内存对齐的老铁就会明白,这个结构体的大小的确是12,但是绝不是简单意义上的大小,言外之意:这道题是个大坑!

(3)我的代码提问

我当时写了一个文档发给了这位同学

int main()
{struct a{int x;char y[4];float z;};//一种朴素的想法当然是4+4+4啦,但是肯定不对……//不信你看这个程序printf("%zd\n", sizeof(struct a));//输出的也是12啊,怎么不对了?是的,不对,这个只是巧合,因为成员刚好大小都是4个字节,这与放了三个int成员是没有太大区别//但是如果是不同的就涉及到结构体内存对齐的问题了//假设我们将结构体内部成员换一下,存在一个char类型的成员struct b{char i;int x;char y[4];float z;};//按照直接加的逻辑,就是1+4+4+4==13printf("%zd\n", sizeof(struct b));//你会发现结果是16!//如果可以系统了解一下结构体对齐的知识吧,需要的话我可以发个链接给你//但是这道题由于成员设置的比较简单(因为结构体成员的类型都是4个字节)直接简单相加得到的结果确实是对的,都是这样的理解方式是有问题的!!return 0;
}

001、结构体内存对齐规则

(1)规则一:第一个成员变量在结构体变量偏移量为0的地址处

(2)规则二:其他成员变量要对齐到“对齐数”的整数倍的地址处(每个成员拥有一个对齐数,对齐数==“编译器默认的一个对齐数(VS默认这个数是8)”与“该成员大小”的较小值)

(3)规则三:结构体的总大小为最大对齐数(每个成员对齐数最大的)整数倍处

(4)规则四:如果嵌套了结构体,先计算这个被内嵌的结构体大小,然后将这个被内嵌的结构体整体当成一个新类型就行

002、为什么存在内存对齐?

(1)性能原因

数据结构应该尽可能的在自然边界上对齐。如果处理器访问了没有对齐的内存,可能需要多次访问内存空间才能得到一个完整的数据

(2)平台原因

不是所有平台都可以访问任意地址上的数据的,某些硬件平台只能在某些地址取出某些特定类型的数据,否则抛出硬件异常

(3)实质原因

牺牲空间换时间的做法

003、结构体大小推导例子

(1)例子一

struct S1
{char c1;//char大小为1,和默认对齐数8比,该成员的成员对齐数是1char c2;//char大小为1,和默认对齐数8比,该成员的成员对齐数是1int i;//整型大小为4,和默认对齐数8比,该成员的成员对齐数是4
};//最大成员对齐数是4,结构体总大小必须是4的倍数
printf("%d\n", sizeof(struct S1));//结果为8

在这里插入图片描述

(2)例子二

struct S2
{char c1;//大小为1,和默认对齐数比,该成员的成员对齐数是1int i;//大小为4,和默认对齐数比,该成员的成员对齐数是4char c2;//大小为1,和默认对齐数比,该成员的成员对齐数为1
};//最大成员对齐数是4,结构体的总大小必须是4的倍数
printf("%d\n", sizeof(struct S2));//结果为12,注意不是9,因为要满足规则三

在这里插入图片描述

(3)例子三

//嵌套结构体
struct S3
{double d;//大小为8,和默认对齐数8相比,该成员的成员对齐数为8char c;//大小为1,与默认对齐数8相比,该成员的成员对齐数为1int i;//大小为4,与默认对齐数8相比,该成员的成员对齐数为4
};//最大成员对齐数为8,结构体的总大小必须是8的倍数
printf("%d\n", sizeof(struct S3));//输出16struct S4
{char c1;//大小为1,与默认对齐数8相比,该成员的成员对齐数为1struct S3 s3;//大小为16,与默认对齐数8相比,该成员的成员对齐数为8double d;//大小为8,与默认对齐数8相比,该成员的成员对齐数为8
};//最大成员对齐数为8,结构体的总大小必须是8的倍数
printf("%d\n", sizeof(struct S4));//值为32

S3的大小
在这里插入图片描述
S4的大小
在这里插入图片描述

004、在VS2022中如何修改默认对齐数?

(1)使用#pragma

利用#pragma这个预处理指令就可以改变默认对齐数

(2)具体代码

使用#pragma的具体代码(这里的代码可以自己尝试画图解决)

①代码一

#include <stdio.h>
#pragma pack(8)//把默认对齐数设置为8
struct S1
{char c1;//char大小为1,和设置后的默认对齐数8比,该成员的成员对齐数是1char c2;//char大小为1,和设置后的默认对齐数8比,该成员的成员对齐数是1int i;//整型大小为4,和设置后的默认对齐数8比,该成员的成员对齐数是4
};//最大成员对齐数是4,结构体大小必须是4的倍数
#pragma pack()//取消设置的默认对齐数,还原为默认值int main()
{printf("%d\n", sizeof(struct S1));//结果为8
}

②代码二

#pragma pack(1)//设置默认对齐数为1
struct S2
{char c1;//大小为1,和设置后的默认对齐数1比,该成员的成员对齐数是1int i;//大小为4,和设置后的默认对齐数1比,该成员的成员对齐数是1char c2;//大小为1,和设置后的默认对齐数1比,该成员的成员对齐数为1
};//最大成员对齐数是1,结构体大小必须是1的倍数
#pragma pack()//取消设置的默认对齐数,还原为默认int main()
{printf("%d\n", sizeof(struct S2));//结果为6return 0;
}

这里注意,当默认对齐数为1的时候,此时对结构体成员进行简单加法运算得到结构体大小是没有问题的

005、注意

如果你认真看完了上面的内容,你就会发现这里面最重要的就是对齐数的确认,而编译器自身携带的默认对齐数更是会直接影响结构体的的大小。

然而现实是,不同的编译器的默认对齐数有可能是不一样的,甚至有的编译器直接就没有这方面的规定!!!例如下面这一串代码

#include <stdio.h>
int main()
{//嵌套结构体struct S3{double d;char c;long double i;};printf("%d\n", sizeof(struct S3));struct S4{char c1;struct S3 s3;double d;};printf("%d\n", sizeof(struct S4));return 0;
}

(1)VS环境下

在这里插入图片描述

(2)在vscode使用mingw64的gcc工具环境下

在这里插入图片描述

据听说,本题还被作为考试题目,当作检验C语言课程学习来使用???如果讲了也就罢了,若是没讲,就算考生得到12这个结果(指开头的题目),真的不会影响他对结构体内存的理解么?私认为,本题目不够严谨……

相关文章:

结构体内存大小

000、前言 要想计算结构体内存大小&#xff0c;就会涉及到一个结构体内存对齐的问题&#xff0c;而不是对其成员进行简单的加运算 &#xff08;1&#xff09;在写本博客之前 有位同学和我讨论了一个学校的题目&#xff0c;题目如下&#xff1a; 我借这道题目问了另外一位同…...

gerrit操作和jinkens编译合入代码

gerrit 先 查看自己的push 找到后添加reviewer 填写邮箱开头就可以出来 记得1 然后send 让人review 编译不过&#xff0c;gerrit上查看 1.是不是checkstyle问题 2.编译不过&#xff0c;去jinkens查看 先retrigger重新编译 如果发现多次编译失败 则要看下console output 查…...

网络工程师面试题(面试必看)(3)

作者简介:一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 前言 本系列将会提供网络工程师面试题,由多位专家整合出本系列面试题,包含上百家面试时的问题。面试必考率达到80%,本系列共86道题…...

第N次重装系统之Ubtntu

前言又一次换了服务器&#xff0c;由于centOS已经完成了自己的生命周期&#xff0c;接下来我会转去使用Ubtntu系统。当然&#xff0c;大部分docker命令是不会收到影响的&#xff0c;但是一部分安装过程可能就要重新学习了。其实这个系统也有自己的老牌包管理器apt&#xff0c;所…...

一个 适用 vue3 ts h5移动端 table组件

vue3-h5-table 介绍 适用于 vue3 ts 的 h5 移动端项目 table 组件 支持 左侧固定 滑动 每行点击回调 支持 指定列排序 链接 &#xff1a;https://github.com/duKD/vue3-h5-table 效果 props说明minTableHeight表格最小高度 可选 默认600rowNum表格显示几行 可选 默认 6he…...

Vue.js 生产打包上线实战

项目管理后台采用Vue.js 架构&#xff0c;开发完毕后设计到打包上传到服务器发布。 发布成功后&#xff0c;总结出主要要决绝两个主要问题&#xff1a; 1.打包前&#xff0c;环境设置 2.上传到服务器&#xff0c;直接放在Tomcat中出现跨域访问问题。 此次项目实际处理方法为…...

C语言指针的算术运算

C语言指针的算术运算 C语言中&#xff0c;指针是一种非常重要的数据类型。除了可以指向特定的内存地址外&#xff0c;指针还可以进行算术运算。指针的算术运算包括加、减、比较等操作&#xff0c;下面我们将详细介绍这些运算符的使用方法&#xff0c;并提供实际的示例。 指针…...

快速排序/快速选择算法

一.快速排序 1.基本介绍 快速排序&#xff08;Quicksort〉是对冒泡排序的一种改进,都属于交换排序。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分(每次选择中轴值)&#xff0c;中轴值左边的元素小于中轴值,中轴值右边的元素全部大于中轴值(但不要求有序)&#x…...

【数据结构初阶】单链表面试题|内含链表带环问题

目录 前言 链表面试题 1. 删除链表中等于给定值 val 的所有节点。oj链接 2.反转一个单链表。oj链接 3. 给定一个带有头结点 head 的非空单链表&#xff0c;返回链表的中间结点。如果有两个中间结点&#xff0c;则返回第二个中间结点。oj链接 4. 输入一个链表&#xff0c;…...

一文解析ethtool 命令的使用

命令简介 ethtool命令用于查询和控制网络设备驱动程序和硬件设置&#xff0c;尤其是有线以太网设备&#xff0c;devname网卡的名称。网卡就像是交换机的一个端口&#xff0c;正常使用我们只是配置网卡IP地址等信息&#xff0c;网卡的速率、双工模式等我们并不关心。通过ethtoo…...

深度学习训练营之yolov5训练自己的数据集

深度学习训练营之训练自己的数据集原文链接环境介绍准备好数据集划分数据集运行voc_train.py遇到问题完整代码创建new_data.yaml文件模型训练时遇到的报错模型训练结果可视化参考链接原文链接 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f…...

Java中的AQS

文章目录什么是AQSAbstractQueuedSynchronizer方法解析自旋与阻塞ReentrantLock&#xff0c;Semaphore以及CountDownLatch对比ReentrantLock实现原理原理ReentrantLock源码中compareAndSetState的方法Semaphore实现原理CountDownLatch实现原理什么是AQS AQS是Java中的一个抽象…...

Spring——案例-业务层接口执行效率和AOP通知获取数据+AOP总结

执行时间获取:记录开始时间和结束时间&#xff0c;取差值。 这里使用环绕通知来实现。 环境准备: 项目文件结构: 业务层接口和实现类: 数据层: 采用mybatis注解开发&#xff0c;这里没有实现类&#xff0c;直接在接口方法里面实现映射。 domain层: 实现了数据库里面每一个…...

国外SEO舆情处理最佳黄金时间

在国外市场&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;的舆情处理是非常重要的&#xff0c;因为它可以帮助提高网站的排名和流量&#xff0c;并且建立品牌的声誉和信誉。 然而&#xff0c;在什么时间进行舆情处理是一个值得探讨的问题。 在本文中&#xff0c;我们将…...

ROC和AUC

目录 ROC AUC ROC ROC曲线是Receiver Operating Characteristic Curve的简称&#xff0c;中文名为"受试者工作特征曲线"。ROC曲线的横坐标为假阳性率(False Postive Rate, FPR)&#xff1b;纵坐标为真阳性率(True Positive Rate, TPR).FPR和TPR的计算方法分别为 F…...

Dopamine-PEG-cRGD,DOPA-PEG-cRGD,多巴胺-聚乙二醇-crgd细胞穿膜肽

名称:多巴胺-聚乙二醇-cRGD穿膜肽,多巴胺-聚乙二醇-crgd细胞穿膜肽英文名称:Dopamine-PEG-cRGD,DOPA-PEG-cRGD规格:50mg,100mg,150mg(根据要求可定制&#xff09;描述&#xff1a;cRGD多肽序列: cyclo(RGDfK)外 观 : 半固体或固体&#xff0c;取决于分子量。溶解性&#xff1a;…...

动态规划回文子串

647. 回文子串方法&#xff1a;双指针回文子串有长度为奇数和偶数两种&#xff0c;extend(s, i, i, n); extend(s, i, i 1, n);就分别对应长度为奇数和偶数的情况class Solution { private:int extend(const string& s, int i, int j, int n) {int res 0;while (i > 0…...

windows 域控提权CVE-2014-6324CVE-2020-1472CVE-2021-42287CVE-2022-26923

一、CVE-2014-6324复现 环境&#xff1a;god.org域&#xff0c;两台主机&#xff0c;一台win2008域控&#xff0c;另一台web服务器win2008 工具&#xff1a;ms14-068.exe(漏洞exp) mimikatz psexec 利用条件&#xff1a; 1.域用户账号密码 2.获得一台主机权限(本地administ…...

1、JDK 安装 Java环境变量配置

jdk下载&#xff08;Java8&#xff09; &#xff08;下载时间不同&#xff0c;小版本号会有变化&#xff0c;不影响后续安装&#xff09; 官网下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads/#java8-windows 下载完后安装 JDK 环境变量配置 Win…...

[c++]list模拟实现

目录 前言&#xff1a; 学习类的方式&#xff1a; 1 类成员变量 1.1 list成员变量 1.2 结点结构体变量 1.3 迭代器成员变量 2 默认函数——构造 2.1 结点结构体构造函数 2.2 list构造函数 2.3 迭代器构造函数 3 迭代器实现 3.1 list部分 3.2 迭代器结构体部分 3.2…...

实用的仓库管理软件有哪些,盘点2023年5大仓库管理软件!

对于做批发生意的老板或工厂老板来说&#xff0c;选择一款实用的仓库管理软件是至关重要的。仓库管理软件除了可以帮你降低仓库管理成本&#xff0c;提高经营管理的效率&#xff0c;还能够在手机上随时随地掌控仓库员工和商品的最新信息&#xff0c;与客户、供应商的订单情况能…...

(八十二)透彻研究通过explain命令得到的SQL执行计划(1)

今天我们正式进入研究explain命令得到的SQL执行计划的内容了&#xff0c;只要把explain分析得到的SQL执行计划都研究透彻&#xff0c;完全能看懂&#xff0c;知道每个执行计划在底层是怎么执行的&#xff0c;那么后面学习SQL语句的调优就非常容易了。 首先&#xff0c;我们现在…...

【Linux】旋转锁 | 读写锁

在之前的线程学习中&#xff0c;用到的锁都是挂起等待锁&#xff0c;如果申请不到锁&#xff0c;那就会在锁中等待&#xff1b; 自旋锁则不大相似 文章目录1.自旋锁1.1 概念1.2 接口1.2.1 pthread_spin_init/destroy1.2.2 pthread_spin_lock1.2.3 pthread_spin_unlock2.读写锁…...

EasyExcell导出excel添加水印

EasyExcell导出excel添加水印1、添加easyExcel相关依赖2、准备基础工具类3、创建水印handler类4、创建单元测试类WriteTest.class5、测试结果1、添加easyExcel相关依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId&…...

SpringCloud:Nacos配置管理

Nacos除了可以做注册中心&#xff0c;同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多&#xff0c;达到数十、数百时&#xff0c;逐个修改微服务配置就会让人抓狂&#xff0c;而且很容易出错。我们需要一种统一配置管理方案&#xff0c;可以集中管理…...

正则表达式引擎NFA自动机的回溯解决方案总结

前几天线上一个项目监控信息突然报告异常&#xff0c;上到机器上后查看相关资源的使用情况&#xff0c;发现 CPU 利用率将近 100%。通过 Java 自带的线程 Dump 工具&#xff0c;我们导出了出问题的堆栈信息。 我们可以看到所有的堆栈都指向了一个名为 validateUrl 的方法&#…...

卷积神经网络之AlexNet

目录概述AlexNet特点激活函数sigmoid激活函数ReLu激活函数数据增强层叠池化局部相应归一化DropoutAlexnet网络结构网络结构分析AlexNet各层参数及其数量模型框架形状结构关于数据集训练学习keras代码示例概述 由于受到计算机性能的影响&#xff0c;虽然LeNet在图像分类中取得了…...

React中setState什么时候是同步的,什么时候是异步的?

本文内容均针对于18.x以下版本 setState 到底是同步还是异步&#xff1f;很多人可能都有这种经历&#xff0c;面试的时候面试官给了你一段代码&#xff0c;让你说出输出的内容&#xff0c;比如这样&#xff1a; constructor(props) {super(props);this.state {val: 0}}compo…...

优秀开源软件的类,都是怎么命名的?

日常编码中&#xff0c;代码的命名是个大的学问。能快速的看懂开源软件的代码结构和意图&#xff0c;也是一项必备的能力。 Java项目的代码结构&#xff0c;能够体现它的设计理念。Java采用长命名的方式来规范类的命名&#xff0c;能够自己表达它的主要意图。配合高级的 IDEA&…...

绘制CSP的patterns矩阵图

最近在使用FBCSP处理数据,然后就想着看看处理后的样子,用地形图的形式表现出来,但是没有符合自己需求的函数可以实现,就自己尝试的实现了一下,这里记录一下,方便以后查阅。 绘制CSP的patterns矩阵图 对数据做了FBCSP处理,但是想画一下CSP计算出来的patterns的地形图,并…...