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

相关文章

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

使用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

Oracle存储过程里操作BLOB的字节数据的办法

《Oracle存储过程里操作BLOB的字节数据的办法》该篇文章介绍了如何在Oracle存储过程中操作BLOB的字节数据,作者研究了如何获取BLOB的字节长度、如何使用DBMS_LOB包进行BLOB操作... 目录一、缘由二、办法2.1 基本操作2.2 DBMS_LOB包2.3 字节级操作与RAW数据类型2.

基于Spring实现自定义错误信息返回详解

《基于Spring实现自定义错误信息返回详解》这篇文章主要为大家详细介绍了如何基于Spring实现自定义错误信息返回效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录背景目标实现产出背景Spring 提供了 @RestConChina编程trollerAdvice 用来实现 HTT

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

springMVC返回Http响应的实现

《springMVC返回Http响应的实现》本文主要介绍了在SpringBoot中使用@Controller、@ResponseBody和@RestController注解进行HTTP响应返回的方法,... 目录一、返回页面二、@Controller和@ResponseBody与RestController

golang内存对齐的项目实践

《golang内存对齐的项目实践》本文主要介绍了golang内存对齐的项目实践,内存对齐不仅有助于提高内存访问效率,还确保了与硬件接口的兼容性,是Go语言编程中不可忽视的重要优化手段,下面就来介绍一下... 目录一、结构体中的字段顺序与内存对齐二、内存对齐的原理与规则三、调整结构体字段顺序优化内存对齐四、内

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(