C语言结构体位域

news2025/1/22 2:13:54

目录

一、C语言位域是什么?

二、位域详解

定义格式:

1. 数据类型排序改变,位域长度不变

2. 数据类型排序不变,位域长度改变

3.根据以上代码的验证可以得出以下计算位域结构体数据的方法:

三.位域的结构体数据如何进行printf打印 ?

四、位域

五、网络数据包

总结


一、C语言位域是什么?


有时候,信息存储的时候,并不需要一个完整的字节,而只需占几个或一个二进制位就能满足需求。例如存放一个bool类型的变量,只需要true或者false即可,这种情况下,只需要0或者1一位二进制位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

二、位域详解

定义格式:

struct 位域结构名 
{ 
 
    类型  位域名:位域长度
 
}; 

其中位域列表的形式为: 类型说明符 位域名:位域长度 

例如:

1. 数据类型排序改变,位域长度不变

  • (排序情况: int,int,char)
typedef struct struct_threshold_test
{
    int     VariableOne:  1;    // 取1位
    int     VariableTwo:  4;    // 取4位
    char    VariableThree:2;    // 取2位
}threshold_struct;

打印情况:
    The struct "threshold_test" size = 8    

  • (排序情况: int,char,int)
typedef struct struct_threshold_test
{
    int     VariableOne:  1;    // 取1位
	char    VariableThree:2;    // 取2位
    int     VariableTwo:  4;    // 取4位
    }threshold_struct;

打印情况:
    The struct "threshold_test" size = 12
  • (排序情况: char,int,int)
typedef struct struct_threshold_test
{
	char    VariableThree:2;    // 取2位
    int     VariableOne:  1;    // 取1位
    int     VariableTwo:  4;    // 取4位
    }threshold_struct;

打印情况:
    The struct "threshold_test" size = 8

2. 数据类型排序不变,位域长度改变

  • (位域长度依次为: 1, 4, 2)
typedef struct struct_threshold_test
{
    int     VariableOne:  1;    // 取1位
    int     VariableTwo:  4;    // 取4位
    char    VariableThree:2;    // 取2位
}threshold_struct;

打印情况:
    The struct "threshold_test" size = 8    

  • (位域长度依次为: 16, 16, 8)
typedef struct struct_threshold_test
{
    int     VariableOne:  16;    // 取16位
    int     VariableTwo:  16;    // 取16位
    char    VariableThree:8;     // 取8位
}threshold_struct;

打印情况:
   The struct "threshold_test" size = 8    

  • (位域长度依次为: 16, 17, 8)
typedef struct struct_threshold_test
{
    int     VariableOne:  16;    // 取16位
    int     VariableTwo:  17;    // 取17位
    char    VariableThree:8;     // 取8位
}threshold_struct;

打印情况:
   The struct "threshold_test" size = 12  

3.根据以上代码的验证可以得出以下计算位域结构体数据的方法:

(1)第一步,根据结构体数据里面所有的基本数据类型中占用存储空间最大的基本数据类型作字节对齐。
(2)第二步,如果相邻的基本数据类型一致,则查看两者的位域长度之和是否大于此数据类型的存储空间,大于则两者之和的大小为两个此类型的存储空间;小于等于则两者之和的大 小为单个此类型的存储空间。
如果相邻的数据类型不一致,则以占用存储空间最大的基本数据类型作字节对齐。
(3)第三步, 根据第一、二步计算总大小。

三.位域的结构体数据如何进行printf打印 ?

  1. 首先,我们来看一下以下代码的打印值
typedef struct struct_threshold_test
{
    int     VariableOne:  1;    // 取1位  
    int     VariableTwo:  4;   // 取4位
    char    VariableThree:2;    // 取2位
}threshold_struct;

int main()
{ 
/**1. 声明一个位域结构体threshold_test*/
    threshold_struct threshold_test;

/** 2. 赋值*/
    threshold_test.VariableOne   = 1;  // 二进制表示 1
    threshold_test.VariableTwo   = 15; // 二进制表示 1111
    threshold_test.VariableThree = 2;  // 二进制表示 10
    
/** 3. 打印值*/
    printf("threshold_test.VariableOne   = %d\n",threshold_test.VariableOne);
    printf("threshold_test.VariableTwo   = %d\n",threshold_test.VariableTwo);
    printf("threshold_test.VariableThree = %d\n",threshold_test.VariableThree);
    
    return 0;
}

//打印情况:
    threshold_test.VariableOne   = -1
    threshold_test.VariableTwo   = -1
    threshold_test.VariableThree = -2

奇怪,为什么我的打印不是 1,15,2呢?怎么会是 -1, -1, -2呢? 明明 1的二进制就是一个bit(1), 15的二进制是4个bit(1000), 2的二进制是 2个bit( 10). 怎么%d打印的跟我设置的
变量不同呢???
其实原因在于,在有符号的基本数据类型定义的变量中,需要有一个bit来保存正负的标志, 要想打印正常,只需要将上述变量的位域长度增加1,即可正常打印。
当然啦,也可以将变量定义为无符号类型,就不需要增加1个位也可以进行正常打印,如下:

typedef struct struct_threshold_test
{
    unsigned int    VariableOne:  1;    //   
    unsigned int    VariableTwo:  4;   //
    unsigned char   VariableThree:2;    // 
}threshold_struct;

int main()
{ 
/**1. 声明一个位域结构体threshold_test*/
    threshold_struct threshold_test;

/** 2. 赋值*/
    threshold_test.VariableOne   = 1;  // 二进制表示 1
    threshold_test.VariableTwo   = 15; // 二进制表示 1111
    threshold_test.VariableThree = 2;  // 二进制表示 10
    
/** 3. 打印值*/
    printf("threshold_test.VariableOne   = %d\n",threshold_test.VariableOne);
    printf("threshold_test.VariableTwo   = %d\n",threshold_test.VariableTwo);
    printf("threshold_test.VariableThree = %d\n",threshold_test.VariableThree);
    
    return 0;
}

//打印情况:
    threshold_test.VariableOne   = 1
    threshold_test.VariableTwo   = 15
    threshold_test.VariableThree = 2


四、位域


位域的定义有以下几点说明: 
1. 一个位域需存储在同一个单元中,不能跨两个单元,如果一个单元剩余空间不够存放另一位域时,需从下一单元起存放该位       域。也可以使某位域从下一单元开始。

例如: 

typedef struct _net_pro_cdu  
{ 
    unsigned  char acs:4 
    unsigned  char :0  
    unsigned  char ace:4  
    unsigned  char dve:4 
} Ncdu;

这个位域定义中,acs占第一字节的4位,后4位填0表示不使用,ace从第二字节开始,占用4位,dve占用4位。 


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

例如: 

typedef struct _can_pro_ndu 
{ 
    unsigned int a:1 
    unsigned int :2  
    unsigned int b:3 
    unsigned int c:2 
} ndu; 

可以看出,位域其实就是一种结构类型, 只不过成员占用空间大小是按Bit分配的。
简言之,这是位域操作的表示方法,位域名后面“:1”的表示结构体变量的大小占所定义类型的1 bit,“:2”占2 bit,依次类推。但是大小不能超过所定义类型包含的总bit数。 
一个Bytes(字节)是8 Bit(bit)。你的结构体中定义的类型是u_char,一个字节,共8bit,最大就不能超过8。 
32位机下, 
short是2字节,16Bit,最大就不能超过16。
int是4字节,32Bit,最大就不能超过32。
依次类推。 

五、网络数据包

 上图是网络数据包的定义,如果我们要定义这个数据包,可以如下定义方式:

typedef struct _net_pro_union {
    unsigned char cvs;
    unsigned char code:4;
    unsigned char dis:2;
    unsigned char div:2;
    unsigned char res:6;
    unsigned char acs:1;
    unsigned char ace:1;
    unsigned char pdc;
} NDU;

测试结构体占用空间:

#include<stdio.h>
#include<stdlib.h>
 
typedef struct _net_pro_union {
    unsigned char cvs;
    unsigned char code:4;
    unsigned char dis:2;
    unsigned char div:2;
    unsigned char res:6;
    unsigned char acs:1;
    unsigned char ace:1;
    unsigned char pdc;
} NDU;
 
 
int main()
{
    NDU ndu;
    unsigned int size = sizeof(ndu);
    printf("size = %u\n", size);
}

在64位机上测试该结构体大小,经测试,占用空间:

 为4字节。

总结

这种定义方式,极大的节省了空间,应用场景多为网络数据包格式定义,我们在收包解包的时候使用比较多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/519825.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

感恩有你:毕业论文致谢部分写作指南

现在正值毕业论文写作最后收尾阶段&#xff0c;估计很多同学开始各处收集如何写致谢这个部分。之前写过一篇文章中引用一位导师的“抱怨”&#xff0c;文章题目为“211导师深夜含泪发文&#xff1a;在你长达5万字的毕业论文中&#xff0c;我最欣赏致谢部分”&#xff0c;所以为…

Java面试题spring

Spring 1、不同版本的 Spring Framework 有哪些主要功能&#xff1f; 2、什么是 Spring Framework&#xff1f; Spring 是一个开源应用框架&#xff0c;旨在降低应用程序开发的复杂度。它是轻量级、松散耦合的。 它具有分层体系结构&#xff0c;允许用户选择组件&#xff0c…

国考省考行测:资料分析题,年均增长量

国考省考行测&#xff1a;资料分析题&#xff0c;年均增长量 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能&#xff0c;附带行测和申论&#xff0c;而常规国考省考最重要的还是申论和行测&#xff0c;所以大家认真准备吧&#xff0c;我讲一起屡屡申…

Docker基础篇

1、为什么Docker比VM快 2、帮助启动类命令 启动类命令 启动docker&#xff1a; systemctl start docker停止Docker&#xff1a; systemctl stop docker重启Docker&#xff1a; systemctl restart docker查看状态&#xff1a; systemctl status docker设置开机自启&#x…

stable diffusion webui 教程:安装与入门

stable diffusion webui 安装与入门 一、源码仓库二、模型库地址三、在 Windows 上自动安装步骤安装Python安装git下载源代码编辑 webui-user.bat 四、如何打开五、依据文字生成图片六、API在哪里&#xff1f;七、用python调用API接口示例八、如何制作生成精美的图片1、下载模型…

Qt--多窗口编程

目录 1. QMessageBox 消息对话框&#xff08;掌握&#xff09; 示例代码&#xff1a; dialog.h dialog.cpp dialog.ui 运行结果&#xff1a; 2. 窗口类继承关系 dialog.cpp 3. QMainWindow 主窗口类 3.1 QMenuBar 菜单栏 3.2 QToolBar 工具栏 3.3 QWidget 中心组件 3.4 QStatu…

外强中干——双向带头循环链表

前言&#xff1a;众所周知&#xff0c;链表有八种结构&#xff0c;由单向或双向&#xff0c;有头或无头&#xff0c;循环或不循环构成。在本篇&#xff0c;将介绍8种链表结构中最复杂的——双向带头循环链表。听着名字或许挺唬人的&#xff0c;但实际上双向带头循环链表实现起来…

九盾安防智能叉车管理系统告诉你叉车电池安全使用的十要点

叉车电池是叉车的动力源&#xff0c;对于保证叉车安全运行具有非常重要的作用。但是&#xff0c;叉车电池在使用过程中也会存在一些安全问题&#xff0c;如果使用不当可能会引起严重后果。下文就九盾安防智能叉车管理系统介绍叉车电池安全使用的十要点。 一、保证通风良好。在使…

课程《JavaWeb基础框架程序设计》考试题下篇——数据库与表单操作用题(人事管理平台的添加员工档案信息的操作题)

文章目录 &#x1f4cb;前言&#x1f3af;第三题&#xff08;40分&#xff09;&#x1f3af;报错以及解决方法&#x1f4dd;最后 &#x1f4cb;前言 这篇文章是大学课程《JavaWeb基础框架程序设计》考试题目的内容&#xff0c;包括了原题和答案。题目只包括了三道编程题&#…

2直接连接的网络与VLAN划分-2.3【实验】【计算机网络】

2直接连接的网络与VLAN划分-2.2-2.3【实验】【计算机网络】 前言推荐2直接连接的网络与VLAN划分2.1共享式以太网和交换式以太网2.2交换机MAC地址表建立与帧转发2.3 STP工作过程实验目的实验内容及实验环境实验原理物理环路引发的问题1:广播风暴物理环路引发的问题2:MAC地址表翻…

ChatGPT之公文写作

公务文章主要适用于政府部门、机关、事业单位以及其他公共组织的文件、公告、通知等文稿。 根据《党政机关公文处理工作条例》&#xff0c;公文种类主要有15种。按照行文流向&#xff0c;可以分为上行文、平行文、下行文。 1、上行文&#xff1a;请示、报告、意见。 2、平行…

Qt 文件IO

目录 1. QFileDialog 文件选择对话框 示例代码 dialog.h dialog.cpp dialog.ui 运行效果&#xff1a; 2. QFileInfo 文件信息类 dialog.cpp 3. QFile 文件读写类 UI与耗时操作 QThread 线程类 1 复现阻塞 dialog.h dialog.cpp 2.新建并启动子线程 mythread.h mythread.cpp dial…

Py之tf2onnx:tf2onnx库的简介、安装、使用方法之详细攻略

Py之tf2onnx&#xff1a;tf2onnx库的简介、安装、使用方法之详细攻略 目录 tf2onnx库的简介 tf2onnx库的安装 tf2onnx库的使用方法 1、基础用法 tf2onnx库的简介 tf2onnx是一个将TensorFlow&#xff08;tf-1.x或tf-2.x&#xff09;、keras、tensorflow.js和tflite模型转换…

【python安装】linux环境安装python

linux环境安装python 小白都能看懂的python安装前置步骤下载python安装python 小白都能看懂的python安装 前置步骤 使用 python -V 或者 python -version 查看是否安装python如果Linux有python3需要更新指定版本的话&#xff0c;先把自带的删除&#xff0c;输入 rpm -qa|grep…

JavaScript通过js的方式来计算平行四边形的面积的代码

以下为通过js的方式来计算平行四边形的程序代码和运行截图 目录 前言 一、通过js的方式来计算平行四边形&#xff08;html部分&#xff09; 1.1 运行流程及思想 1.2 代码段 二、通过js的方式来计算平行四边形&#xff08;js部分&#xff09; 2.1 运行流程及思想 2.2 代码…

算法修炼之练气篇——练气六层

博主&#xff1a;命运之光 专栏&#xff1a;算法修炼之练气篇 前言&#xff1a;每天练习五道题&#xff0c;炼气篇大概会练习200道题左右&#xff0c;题目有C语言网上的题&#xff0c;也有洛谷上面的题&#xff0c;题目简单适合新手入门。&#xff08;代码都是命运之光自己写的…

算法修炼之练气篇——练气十七层

博主&#xff1a;命运之光 专栏&#xff1a;算法修炼之练气篇 前言&#xff1a;每天练习五道题&#xff0c;炼气篇大概会练习200道题左右&#xff0c;题目有C语言网上的题&#xff0c;也有洛谷上面的题&#xff0c;题目简单适合新手入门。&#xff08;代码都是命运之光自己写的…

SpringBoot+Token+Redis+Lua+自动续签极简分布式锁Token登录方案

前言 用SpringBoot做一个项目&#xff0c;都要写登录注册之类的方案 使用Cookie或Session的话&#xff0c;它是有状态的&#xff0c;不符合现代的技术 使用Security或者Shiro框架实现起来比较复杂&#xff0c;一般项目无需用那么复杂 使用JWT它虽然是无状态的&#xff0c;也可…

微信开发者之AppID和AppSecret举例子

-- 请不要为爱你的人流泪&#xff0c;因为爱你的人不会让你流泪&#xff01; 序 今天对这2东西做个相对全面的介绍&#xff0c;不一定深入&#xff0c;但是对实际开发还是很有必要的 我们在微信开发中总是会绕不开2个单词&#xff1a; AppID&#xff1a;开发者ID,有些叫AppK…

蓝桥杯题单day2【题目】

动态规划 调手表https://www.lanqiao.cn/problems/230/learning/?page1&first_category_id1&sortstudents_count&second_category_id3&tags%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92,%E5%9B%BD%E8%B5%9B 最优包含https://www.lanqiao.cn/problems/239/learning…