struct结构体和union联合体:字节对齐下的sizeof返回

2024-05-09 15:38

本文主要是介绍struct结构体和union联合体:字节对齐下的sizeof返回,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先,明白什么是struct结构体,什么事union联合体,以及sizeof

struct和union都属于复合数据结构,其中可以包含多种数据类型,包括int,short,double,甚至数组和struct,union。

既然是数据结构,那么一定需要开辟内存空间用来存储数据,接下来的一切计算过程都是在32windows系统环境进行的。

struct和union的存储是有区别的,前者的内存是成员变量的累加,后者是最大的成员变量所需的空间(这些都要遵循下面讲到的规则),而且前者改变一个成员变量不会影响到另一个,但后者只在开辟的内存中存储最近一次写入的值。另外,struct内的成员变量是连续分布的,这一点也很重要。


基于上面关于struct和union的区别,两者计算sizeof时的规则有些许出入。

接着,说明一下sizeof的用法。sizeof的主要功能就是计算对象或者类型所对应的内存开销,也就是字节个数。在32系统中,char,short,int,long,double对应的内存开销分别是1,2,4,4,8个字节,这也是后面例子中主要用到的基本数据类型。

如果是计算这些基本类型的sizeof的话,应该不难,问题是计算复合数据结构struct和union就有点难度了,因为涉及到一个字节对齐的概念。利用字节对齐的概念,可以在保证合理的空间浪费的前提下,尽可能地提高CPU对数据的访问速度。具体概念请查阅msdn手册。


接下来给出上文提到的计算struct和union的sizeof时要遵守的规则,这些规则是从成员变量地址的角度出发。

对于struct    

特有规则 :

s1. 第一个成员的地址被定义为零。

s2. 除第一个成员的其他成员的首地址都必须可以被自己所对应的数据类型的内存开销(并非成员的大小,而是规则a,b,c的结果)整除,即可能需要在前一个成员变量后补充空字节(也就是被“浪费”的字节).

s3. 所有成员计算完毕后,还要是整个struct的总大小(sizeof结果)可以整除所有成员类型对应的内存开销中的最大值且尽量保持结果尽量小。

对于union

特有规则:

u1. 找出成员中占用字节数最大的,以它作为下限

u2. 找出内存开销最大的成员,然后求其正整数倍数以保证大于条件1中的下限值,同时尽量小。


可以看出两者的基本规则是不同的,但都同时提到两个量:每个成员的内存开销和所有成员开销中最大的值。他们都跟自己的类型有关系,且遵循同一条规则,

共同规则:

a. 无论成员类型是基本的int,char,double,还是复合的struct,union和数据,都只取数据体中的最大的基本数据对应的内存开销。对于int,char这些本来就是基本数据的,取其本身对应的开销值,但是对于struct,union和数据,他们就要进入数据体内分析,应该取数据体中的所有基本类型对应的最大开销值。这里有两点特殊:

b. 数据体还有数据体,那么应该继续深入进去,也就是递归。

c. 基本类型的数组,就当做单独的基本类型看待。


另外,如果有#pragma pack(n)的预处理命令,有规则

t1: 取a,b和c中的求值结果和n的最小者作为结果。


下面给出例子:

<span style="font-size:18px;">#include<iostream>
#define Offset(type,field) ((size_t)&(((type*)0)->field)) //计算struct体内成员的偏移地址()
using namespace std;struct example{double a;
};struct example1
{short a;example b;
};struct example2 
{char a;example1 b;short c;
};struct st1{double a;short b;char c;
};struct st2{char a;st1 b;int c;
};struct st3
{char a;int b[3];char c;
};typedef union{double b;int a;
} unionhelper;
struct st4{unionhelper a;int b;
};typedef union{char a;int b[3];double c;
} un1;typedef union{st4 a;int b[5];
} un2;#pragma pack(4)
struct st5{short a;double b;
};int main()
{//struct//eg1cout<<Offset(st1,a)<<" "<<Offset(st1,b)<<" "<<Offset(st1,c)<<endl; //偏移地址:0,8,10. (对应规则s1和s2)cout<<sizeof(st1)<<endl; //st1的总大小等于16(是8的倍数,对应规则s3)//eg2cout<<Offset(st2,a)<<" "<<Offset(st2,b)<<" "<<Offset(st2,c)<<endl; //偏移地址:0,8,24. (对应规则s1,s2和b)cout<<sizeof(st2)<<endl; //st1的总大小等于32(是8的倍数,对应规则s3和b)//eg3cout<<sizeof(example2)<<endl; //st1的总大小等于32(是8的倍数,对应规则s1,s2,s3和b)//eg4cout<<Offset(st3,a)<<" "<<Offset(st3,b)<<" "<<Offset(st3,c)<<endl; //偏移地址:0,4,16. (对应规则s1,s2和c)cout<<sizeof(st3)<<endl; //st1的总大小等于20(是4的倍数,对应规则s3和c)//eg5cout<<Offset(st4,a)<<" "<<Offset(st4,b)<<endl; //偏移地址:0,8. (对应规则s1,s2和b)cout<<sizeof(st4)<<endl; //st1的总大小等于16(是8的倍数,对应规则s3和b)//union//eg6cout<<sizeof(un1)<<endl; //un1的总大小等于16(是8的倍数,对应规则u1和u2,以及规则a和c)//eg7cout<<sizeof(un2)<<endl; //un1的总大小等于24(是8的倍数,对应规则u1和u2,以及规则a,b,c)//#pragma pack(n)预处理命令cout<<Offset(st5,a)<<" "<<Offset(st5,b)<<endl; //偏移地址:0,4. (对应规则t1)cout<<sizeof(st5)<<endl; //st1的总大小等于12(是4的倍数,对应规则t1)return 0;
}</span>



这篇关于struct结构体和union联合体:字节对齐下的sizeof返回的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/973792

相关文章

mybatis执行insert返回id实现详解

《mybatis执行insert返回id实现详解》MyBatis插入操作默认返回受影响行数,需通过useGeneratedKeys+keyProperty或selectKey获取主键ID,确保主键为自... 目录 两种方式获取自增 ID:1. ​​useGeneratedKeys+keyProperty(推

MySQL中的索引结构和分类实战案例详解

《MySQL中的索引结构和分类实战案例详解》本文详解MySQL索引结构与分类,涵盖B树、B+树、哈希及全文索引,分析其原理与优劣势,并结合实战案例探讨创建、管理及优化技巧,助力提升查询性能,感兴趣的朋... 目录一、索引概述1.1 索引的定义与作用1.2 索引的基本原理二、索引结构详解2.1 B树索引2.2

如何使用Maven创建web目录结构

《如何使用Maven创建web目录结构》:本文主要介绍如何使用Maven创建web目录结构的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录创建web工程第一步第二步第三步第四步第五步第六步第七步总结创建web工程第一步js通过Maven骨架创pytho

Python循环结构全面解析

《Python循环结构全面解析》循环中的代码会执行特定的次数,或者是执行到特定条件成立时结束循环,或者是针对某一集合中的所有项目都执行一次,这篇文章给大家介绍Python循环结构解析,感兴趣的朋友跟随... 目录for-in循环while循环循环控制语句break语句continue语句else子句嵌套的循

SpringBoot中使用Flux实现流式返回的方法小结

《SpringBoot中使用Flux实现流式返回的方法小结》文章介绍流式返回(StreamingResponse)在SpringBoot中通过Flux实现,优势包括提升用户体验、降低内存消耗、支持长连... 目录背景流式返回的核心概念与优势1. 提升用户体验2. 降低内存消耗3. 支持长连接与实时通信在Sp

统一返回JsonResult踩坑的记录

《统一返回JsonResult踩坑的记录》:本文主要介绍统一返回JsonResult踩坑的记录,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录统一返回jsonResult踩坑定义了一个统一返回类在使用时,JsonResult没有get/set方法时响应总结统一返回

MyBatis设计SQL返回布尔值(Boolean)的常见方法

《MyBatis设计SQL返回布尔值(Boolean)的常见方法》这篇文章主要为大家详细介绍了MyBatis设计SQL返回布尔值(Boolean)的几种常见方法,文中的示例代码讲解详细,感兴趣的小伙伴... 目录方案一:使用COUNT查询存在性(推荐)方案二:条件表达式直接返回布尔方案三:存在性检查(EXI

Python struct.unpack() 用法及常见错误详解

《Pythonstruct.unpack()用法及常见错误详解》struct.unpack()是Python中用于将二进制数据(字节序列)解析为Python数据类型的函数,通常与struct.pa... 目录一、函数语法二、格式字符串详解三、使用示例示例 1:解析整数和浮点数示例 2:解析字符串示例 3:解

Python函数返回多个值的多种方法小结

《Python函数返回多个值的多种方法小结》在Python中,函数通常用于封装一段代码,使其可以重复调用,有时,我们希望一个函数能够返回多个值,Python提供了几种不同的方法来实现这一点,需要的朋友... 目录一、使用元组(Tuple):二、使用列表(list)三、使用字典(Dictionary)四、 使

Go 语言中的 Struct Tag 的用法详解

《Go语言中的StructTag的用法详解》在Go语言中,结构体字段标签(StructTag)是一种用于给字段添加元信息(metadata)的机制,常用于序列化(如JSON、XML)、ORM映... 目录一、结构体标签的基本语法二、json:"token"的具体含义三、常见的标签格式变体四、使用示例五、使用