结构体计算大小与位域计算大小

2023-10-27

结构体的大小计算

原则一:结构体的元素按顺序存储,结构体成员的偏移量必须是成员大小的整数倍

原则二:结构体大小是所有成员大小的整数倍(除了内部结构体和数组)

看例子比较快理解,以下是自己的理解

指针的占字节数要看是32还是64位,32占4字节,64位占8个字节

struct X {
    char a;		//1
    char b;		//1
    int c;	//8
};
//这个结构体占8个字节,因为结构体成员中占最大字节数的是int类型,所以成员都要为4的整数倍
//两个char各自占1,因为是顺序存储的,所以两个char可以加起来占2,要和4个字节对其,需补2个字节
//所以最后顺序存储的char、char、int的结构体X占4+4=8个字节
struct X {
    char a;		//1
    int b;		//4
    char c;	//1
};
//结构体占12个字节,因为结构体成员中占最大字节数的是int类型,所以要4的整数倍
//和上面例子的顺序不一样了,第一个char元素补3个字节,最后一个char也要补三个字节
//所以最后顺序存储char、int、char各自都为4字节,即结构体X占4+4+4=12字节
struct X {
    char a;		//1
    int b;		//4
    char c[10];	//10
};
//举个有数组的例子,这个数组是char型,一个char型占一个字节,这个数组就为10个字节
//根据原则二,数组不算成员最大字节数,
//所以这个结构体的成员占最大字节数的类型还是int型,所以要按4的整数倍补齐
//第一个char补3个字节,数组char[10]占10个字节,要为4的整数倍需要补2个字节,所以为12
//最后顺序存储char、int、char[10],所以最后结构体X占4+4+12=20字节
//接下来的例子有两种情况要分析
struct X {
    char a;		//1
    int b;		//4
    struct Y {
        char a;		//1
        int b;		//4
    };
    float;    //4
};
//这个结构体占12个字节,首先我们要知道这个结构体的内部结构体只是声明,所以计算大小会忽略,不占空间
//知道这个很快就知道,里面只计算了顺序存储的char、int、float,所以结构体X占4+4+4=12字节


struct X {
    char a;		//1
    int b;		//4
    struct Y {
        char a;		//1
        int b;		//4
    }temp;
    float;    //4
};
//这是第二种情况,可以看到temp这个变量了,所以这个内部结构体要占空间了
//但是注意一个问题,因为原则二说过了,内部结构体不能当做成员整数倍
//所以这里单纯把内部结构体看成了一个char和一个int,不看整体,这是非常重要的
//最后char、int、char、int、float顺序存储,算出这个结构体X占4+4+4+4+4=20个字节
struct X
    {
        char a;    //1
        int b;    //4
        double c;    //8
    };

struct Y
    {
        char a;        //1
        struct X b;//16
    };
//上个例子说了内部结构体的注意点,但是这个例子有几个地方要注意
//这里的例子要和上个例子区别看清楚,我们要计算结构体Y的大小需要知道X的成员,
//这里先说一下单看结构体X是占16个字节
//如果X的占最大字节数成员有比Y的其他最大字节数的成员大,需要以X的那个为准,比如这里double比char大
//X的成员double是Y里占最大字节数的类型,所以Y的成员都要是8的整数倍
//顺序存储char、X,上个例子的顺序存储可不是这样
//所以总结出,要算结构体Y我们所有成员要以8为整数倍,X看成一个占16字节的成员,这里很重要
//char要补7个字节,而X占16字节已经是8的整数倍了,所以最后结构体Y占8+16=24个字节
//这里如果写成
struct Y
    {
        struct X b;
        char a;
    };
//也是24个字节
struct X
    {
        char a;    //1
        int b;    //4
        union Y{    
            char c;
            int  d;
        };    
    };
//如果是联合体的话就按联合体里占最大字节数那个算
//这里联合体Y占4个字节
//所以最后结构体X占4+4+4=12个字节

 接下来的例子是有#pragma pack指定对其的例子,两个例子即可理解

#pragma pack(4)
struct X
    {
        char a;    //1
        int b;    //4
        float       //4
        double    //8   
    };
//这个例子开头的#pragma pack(4)意思是指定向4对其
//这是第一个例子,我们第一要看的是结构体成员占最大字节数的是什么类型,是否大于指定的数字,这里是4
//这里最大的成员类型是double,8个字节,比指定的4大,所以要按4字节对其
//所以按4字节对其,我们就知道了怎么算结构体大小了
//最后顺序存储char、int、float、double,所以结构体X占4+4+4+8=20个字节
#pragma pack(10)
struct X
    {
        char a;    //1
        int b;    //4
        float       //4
        double    //8   
    };
//和上面例子结构体一致,但是指定了向10对其
//说过了我们第一要看的是结构体成员占最大字节数的是什么类型,是否大于指定的数字,这里是10
//最大的是double占8个字节,比指定的10小,那么就要以8个字节对其了
//最后顺序存储char、int、float、double,所以结构体X占8+8+8=24个字节
//不难看出唯一要注意的地方就是看结构体成员占最大字节数的是什么类型
//是否大于pack指定的数字,大于就按pack指定的对其,小于就按它本身对其

位域的大小计算

介绍:有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为"位域"或"位段"。所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

struct 位域结构名 
{

 位域列表

};
type [member_name] : width ;        // 位域列表的形式

位域的定义有几点需要说明:

1)宽度必须小于或等于指定类型的位宽度

2)一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始

3)位域可以是无名位域,这时它只用来作填充或调整位置。无名的位域是不能使用的

struct k{
    int a:1;
    int  :2;    /* 该 2 位不能使用 */
    int b:3;
    int c:2;
};

接下来是计算大小

1.如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2.如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍
3.如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
4.如果位域字段之间穿插着非位域字段,则不进行压缩;
5. 整个结构体的总大小为最宽基本类型成员大小的整数倍。

直接上例子

struct X
{
    int a1 : 5; 
    int a2 : 5;
    int a3 : 5;
    int a4 : 5;
    int a5 : 5;
};
//这里先来看一下都是同类型的例子
//这里先知道int占4个字节,一个字节8位,所以int有32位
//顺序存储的,所以从上往下看
//可以看到a1占5位,小于32位,所以剩下的27可以给下面的使用
//继续往下看,a2是也是和上面同个类型int,所以可以用上面剩下的27给它用
//a2也用了5位,那么剩下22位可以继续给下面的使用
//以此类推,当a5用完之后,还剩下7位没用,我们不管,小于32位就是4个字节
//所以这个X占4个字节
struct X
{
    int a : 29;
    int b : 29;
    int c : 4;
};
//继续来看一个同类型的例子,根据上面例子的方法,直接来看
//a占29位,剩下3位给下面的使用
//往下看b占29位,而上面是同类型的int,可以用它剩下的
//可是上面的只剩下3位,而b占29不够用,需要开辟新的空间,即4个字节32位
//b也还剩下3位可以给下面继续使用,
//继续看c占4位,可是上面的3位不够用,也要开辟新的空间,即4个字节32位
//所以最后X占4+4+4=12字节
struct X
{
    int a : 1;
    int : 2;    
    int b : 3; 
    int c : 2;
    int d : 3;
    short e : 4; 
    int f : 1;   

};
//这次例子有不同类型了,直接来看和之前不一样的地方
//这里第二个是个空域,单纯补充占大小
//从上往下看,a到d的位算出来1+2+3+2+3=11位,小于32位,剩下21位可以给下面用
//看到e,上面虽然剩下21位够e的4位用,可是类型不一致,所以e要开新的空间,short是4个字节
//同理f和上面的e不是一个类型,开辟新空间
//所以X占4+4+4=12个字节

上面的是个人理解,有说不好的,说错的可以继续改进

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

结构体计算大小与位域计算大小 的相关文章

随机推荐

  • 数据结构与算法 学习摘要

    时间复杂度比较 O 1 lt O logn lt O n lt O nlogn lt O n 2 lt O n 3 线性表 栈 stack 后进先出 队列 queue 先进先出 链表 linkedlist 单链表 双链表 https git
  • Linux8 如何重启网络服务

    本文主要讲解如何重启RHEL 8或者CentOS 8网络以及如何解决RHEL8和CentOS8系统的网络管理服务报错 当我们安装好RHEL 8或者 CentOS 8 重启启动网络时 会出现以下报错 systemctl restart net
  • 板子接线图

    1 ST LINK V2接线 2 对抗板子刷蓝牙固件 接USB转TTL 用镊子短接两个孔 2 对抗板子用串口测试蓝牙AT命令 短接白色箭头 接TX RX 电源
  • 嵌入式开发面试中经常被问到的问题记录

    问题 你能介绍一下你最熟悉的处理器架构及其特点吗 在嵌入式开发中 你通常使用哪些编程语言 对于不同的应用场景 如何选择适合的编程语言 请描述一下您在项目中遇到的最具挑战性的问题 并解释您是如何解决这个问题的 如何设计和实现一个多线程嵌入式系
  • JavaScript:从入门到精通总结二

    7 代码块 1 代码块只有分组的功能 代码块内部的内容 外部完全可见 2 prompt 弹出提示框 并且该提示框会带有一个文本框 返回值是string类型 3 switch语句中条件表达式是进行全等比较 4 可以为循环语句创建一个label
  • spring-data-JPA repository自定义方法规则

    Spring Data JPA框架在进行方法名解析时 会先把方法名多余的前缀截取掉 比如find findBy read readBy get getBy 然后对剩下的部分进行解析 假如创建如下的查询 findByUserDepUuid 框
  • Linux系统管理(五)企业存储的基本管理

    目录 一 设备识别 二 设备挂载 三 设备中文件的查找 四 分区 五 swap分区 六 磁盘配额 一 设备识别 添加硬盘 设备接入系统后都是以文件的形式存在 设备文件名称 串口硬盘 SATA SAS USB dev sda dev sdb
  • 文件共享 无法访问,你可能没有权限使用网络资源,请与这台服务器的管理员联...

    文件或文件夹设置成共享之后 通过 运行 如运行 gt 192 168 0 123 进行访问 报错 192 168 0 123无法访问 你可能没有权限使用网络资源 请与这台服务器的管理员联系 这问题碰到好几回了 每次都是同事帮忙解决的 这次又
  • 什么是xxl-job?

    xxl job是一款开源的分布式任务调度框架 主要用于解决大规模分布式任务的调度和执行问题 它提供了任务调度中心 执行器和任务日志等组件 可以实现任务的定时调度 动态添加和删除任务 任务执行情况的监控和日志记录等功能 xxl job的作用主
  • HTML <ul> 标签

    实例 无序 HTML 列表 ul li Coffee li li Tea li li Milk li ul ul 标签定义无序列表 浏览器支持 元素 Chrome IE Firefox Safari Opera ul Yes Yes Yes
  • cad汉仪长仿宋体_长仿宋体字体下载 cad工程机械绘图工程制图国标字体下载

    做CAD很多时候要用到国标字体 CAD制图上用的国标字体一般就是长仿宋体 特此小编给大家分享 ttf格式的cad工程机械绘图工程制图国标字体下载 长仿宋体字体一般是专门用来做cad工程机械绘制效果图中使用 希望大家喜欢 界面预览图 在很多专
  • zlib库自定义接口封装

    zlib库自定义接口封装 zlib封装类说明 编译zlib库 编译自定义接口静态库 测试代码 代码 文件链接 zlib封装类说明 实现对文件以及文件夹的压缩解压缩 zip unzip h ifndef ZIP UNZIP H define
  • 《剑指offer》:编程实现字符串到整数的装换,模拟实现函数atoi

    题目描述 编程实现字符串到整数的转换 例如输入字符串 123456 输出整数12345 函数atoi atoi 是把字符串转换成整型数的一个函数 包含在头文件stdlib h中 函数原型 int atoi const char nptr 参
  • 电机控制里的谐波和逆变器非线性探讨

    电机控制里的谐波或逆变器非线性探讨 一 逆变器非线性第一个主要原因是死区时间及器件延迟时间 二 逆变器非线性第二原因是功率管的压降 三 逆变器的非线性会引起零电流箝位现象 导致电流波形不够正旋 增大了谐波干扰 并且在一个周期中会有6次电流畸
  • 诚之和:使用Java+Swing实现医院管理系统的实战练习 附完整实例代码

    本篇文章将和大家分享使用Java的Swing工具类来完成医院管理系统的实战练习 有兴趣的小伙伴们可以一起实操学习一下 本文内容有助于大家对于Java的学习和理解 一 系统介绍 本系统实现的以下功能 管理员功能 登录系统 病人信息的增删改查
  • 写一个手机类,属性:品牌brand,价格price 行为:打电话Call,发短信Message,打游戏Game 要用到this和Private的知识点

    初写手机类 这个程序是初步的程序 还有很多细节没补上 等到学到后面再逐渐完善了 class Demond Phone public static void main String args Phone p1 new Phone p1 set
  • centos8 网卡无法启动,且无ip

    centos8 网卡无法启动 且无ip 1 NetworkManger未运行 错误 网络管理器 NetworkManager 未运行 解决 将NetworkManger设置为开机自启动 systemctl enable NetworkMan
  • 《Stable Diffusion WebUI如何下载模型》

    接上一个教程 现在开始使用Stable Diffusion 自己训练模型太花时间了 直接下载别人训练好的模型可以省很多事 左上面stable Diffusion checkpoint就是我们的模型 现在里面什么都没有 1 点击选择上面的Ci
  • map,filter,some,every,find方法的区别(通俗易懂)

    map filter some every都是原数组不受改变 而foreach是在原数组上改变 map 返回新数组 在原数组上进行数据处理 只会在原有数组上元素内容改变 数组长度不变 filter 返回新数组 在原数组上判断是否满足条件来进
  • 结构体计算大小与位域计算大小

    结构体的大小计算 原则一 结构体的元素按顺序存储 结构体成员的偏移量必须是成员大小的整数倍 原则二 结构体大小是所有成员大小的整数倍 除了内部结构体和数组 看例子比较快理解 以下是自己的理解 指针的占字节数要看是32还是64位 32占4字节