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

相关文章

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

Java集合中的链表与结构详解

《Java集合中的链表与结构详解》链表是一种物理存储结构上非连续的存储结构,数据元素的逻辑顺序的通过链表中的引用链接次序实现,文章对比ArrayList与LinkedList的结构差异,详细讲解了链表... 目录一、链表概念与结构二、当向单链表的实现2.1 准备工作2.2 初始化链表2.3 打印数据、链表长

创建springBoot模块没有目录结构的解决方案

《创建springBoot模块没有目录结构的解决方案》2023版IntelliJIDEA创建模块时可能出现目录结构识别错误,导致文件显示异常,解决方法为选择模块后点击确认,重新校准项目结构设置,确保源... 目录创建spChina编程ringBoot模块没有目录结构解决方案总结创建springBoot模块没有目录

SpringBoot利用树形结构优化查询速度

《SpringBoot利用树形结构优化查询速度》这篇文章主要为大家详细介绍了SpringBoot利用树形结构优化查询速度,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一个真实的性能灾难传统方案为什么这么慢N+1查询灾难性能测试数据对比核心解决方案:一次查询 + O(n)算法解决

Django HTTPResponse响应体中返回openpyxl生成的文件过程

《DjangoHTTPResponse响应体中返回openpyxl生成的文件过程》Django返回文件流时需通过Content-Disposition头指定编码后的文件名,使用openpyxl的sa... 目录Django返回文件流时使用指定文件名Django HTTPResponse响应体中返回openp

Oracle查询表结构建表语句索引等方式

《Oracle查询表结构建表语句索引等方式》使用USER_TAB_COLUMNS查询表结构可避免系统隐藏字段(如LISTUSER的CLOB与VARCHAR2同名字段),这些字段可能为dbms_lob.... 目录oracle查询表结构建表语句索引1.用“USER_TAB_COLUMNS”查询表结构2.用“a

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