C语言 位域
C 语言的位域(bit-field)是一种特殊的结构体成员,允许我们按位对成员进行定义,指定其占用的位数。
如果程序的结构中包含多个开关的变量,即变量值为 TRUE/FALSE,如下:
struct
{unsigned int widthValidated;unsigned int heightValidated;
} status;
这种结构需要 8 字节的内存空间,但在实际上,在每个变量中,我们只存储 0 或 1,在这种情况下,C 语言提供了一种更好的利用内存空间的方式。如果您在结构内使用这样的变量,您可以定义变量的宽度来告诉编译器,您将只使用这些字节。例如,上面的结构可以重写成:
struct
{unsigned int widthValidated : 1;unsigned int heightValidated : 1;
} status;
现在,上面的结构中,status 变量将占用 4 个字节的内存空间,但是只有 2 位被用来存储值。如果您用了 32 个变量,每一个变量宽度为 1 位,那么 status 结构将使用 4 个字节,但只要您再多用一个变量,如果使用了 33 个变量,那么它将分配内存的下一段来存储第 33 个变量,这个时候就开始使用 8 个字节。让我们看看下面的实例来理解这个概念:
#include <stdio.h>
#include <string.h>/* 定义简单的结构 */
struct
{unsigned int widthValidated;unsigned int heightValidated;
} status1;/* 定义位域结构 */
struct
{unsigned int widthValidated : 1;unsigned int heightValidated : 1;
} status2;int main( )
{printf( "Memory size occupied by status1 : %d\n", sizeof(status1));printf( "Memory size occupied by status2 : %d\n", sizeof(status2));return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
Memory size occupied by status1 : 8
Memory size occupied by status2 : 4
位域的特点和使用方法如下:
- 定义位域时,可以指定成员的位域宽度,即成员所占用的位数。
- 位域的宽度不能超过其数据类型的大小,因为位域必须适应所使用的整数类型。
- 位域的数据类型可以是 int、unsigned int、signed int 等整数类型,也可以是枚举类型。
- 位域可以单独使用,也可以与其他成员一起组成结构体。
- 位域的访问是通过点运算符(.)来实现的,与普通的结构体成员访问方式相同。
位域声明
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为"位域"或"位段"。
所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
典型的实例:
- 用 1 位二进位存放一个开关量时,只有 0 和 1 两种状态。
- 读取外部文件格式——可以读取非标准的文件格式。例如:9 位的整数。
位域的定义和位域变量的说明
位域定义与结构定义相仿,其形式为:
struct 位域结构名
{位域列表};
其中位域列表的形式为:
type [member_name] : width ;
下面是有关位域中变量元素的描述:
元素 | 描述 |
---|---|
type | 只能为 int(整型),unsigned int(无符号整型),signed int(有符号整型) 三种类型,决定了如何解释位域的值。 |
member_name | 位域的名称。 |
width | 位域中位的数量。宽度必须小于或等于指定类型的位宽度。 |
带有预定义宽度的变量被称为位域。位域可以存储多于 1 位的数,例如,需要一个变量来存储从 0 到 7 的值,您可以定义一个宽度为 3 位的位域,如下:
struct
{unsigned int age : 3;
} Age;
上面的结构定义指示 C 编译器,age 变量将只使用 3 位来存储这个值,如果您试图使用超过 3 位,则无法完成。
struct bs{int a:8;int b:2;int c:6;
}data;
以上代码定义了一个名为 struct bs 的结构体,data 为 bs 的结构体变量,共占四个字节:
对于位域来说,它们的宽度不能超过其数据类型的大小,在这种情况下,int 类型的大小通常是 4 个字节(32位)。
相邻位域字段的类型相同,且其位宽之和小于类型的 sizeo f大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止。
让我们再来看一个实例:
struct packed_struct {unsigned int f1:1;unsigned int f2:1;unsigned int f3:1;unsigned int f4:1;unsigned int type:4;unsigned int my_int:9;
} pack;
以上代码定义了一个名为 packed_struct 的结构体,其中包含了六个成员变量,pack 为 packed_struct 的结构体变量。
在这里,packed_struct 包含了 6 个成员:四个 1 位的标识符 f1…f4、一个 4 位的 type 和一个 9 位的 my_int。
让我们来看下面的实例:
#include <stdio.h>struct packed_struct {unsigned int f1 : 1; // 1位的位域unsigned int f2 : 1; // 1位的位域unsigned int f3 : 1; // 1位的位域unsigned int f4 : 1; // 1位的位域unsigned int type : 4; // 4位的位域unsigned int my_int : 9; // 9位的位域
};int main() {struct packed_struct pack;pack.f1 = 1;pack.f2 = 0;pack.f3 = 1;pack.f4 = 0;pack.type = 7;pack.my_int = 255;printf("f1: %u\n", pack.f1);printf("f2: %u\n", pack.f2);printf("f3: %u\n", pack.f3);printf("f4: %u\n", pack.f4);printf("type: %u\n", pack.type);printf("my_int: %u\n", pack.my_int);return 0;
}
以上实例定义了一个名为 packed_struct 的结构体,其中包含了多个位域成员。
在 main 函数中,创建了一个 packed_struct 类型的结构体变量 pack,并分别给每个位域成员赋值。
然后使用 printf 语句打印出每个位域成员的值。
输出结果为:
f1: 1
f2: 0
f3: 1
f4: 0
type: 7
my_int: 255
#include <stdio.h>
#include <string.h>struct
{unsigned int age : 3;
} Age;int main( )
{Age.age = 4;printf( "Sizeof( Age ) : %d\n", sizeof(Age) );printf( "Age.age : %d\n", Age.age );Age.age = 7;printf( "Age.age : %d\n", Age.age );Age.age = 8; // 二进制表示为 1000 有四位,超出printf( "Age.age : %d\n", Age.age );return 0;
}
当上面的代码被编译时,它会带有警告,当上面的代码被执行时,它会产生下列结果:
Sizeof( Age ) : 4
Age.age : 4
Age.age : 7
Age.age : 0
计算字节数:
#include <stdio.h>struct example1 {int a : 4;int b : 5;int c : 7;
};int main() {struct example1 ex1;printf("Size of example1: %lu bytes\n", sizeof(ex1));return 0;
}
以上实例中,example1 结构体包含三个位域成员 a,b 和 c,它们分别占用 4 位、5 位和 7 位。
通过 sizeof 运算符计算出 example1 结构体的字节数,并输出结果:
Size of example1: 4 bytes
对于位域的定义尚有以下几点说明:
- 一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:
struct bs{unsigned a:4;unsigned :4; /* 空域 */unsigned b:4; /* 从下一单元开始存放 */unsigned c:4
}
在这个位域定义中,a 占第一字节的 4 位,后 4 位填 0 表示不使用,b 从第二字节开始,占用 4 位,c 占用 4 位。
-
位域的宽度不能超过它所依附的数据类型的长度,成员变量都是有类型的,这个类型限制了成员变量的最大长度,: 后面的数字不能超过这个长度。
-
位域可以是无名位域,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
struct k{int a:1;int :2; /* 该 2 位不能使用 */int b:3;int c:2;
};
从以上分析可以看出,位域在本质上就是一种结构类型,不过其成员是按二进位分配的。
位域的使用
位域的使用和结构成员的使用相同,其一般形式为:
位域变量名.位域名
位域变量名->位域名
位域允许用各种格式输出。
请看下面的实例:
#include <stdio.h>int main(){struct bs{unsigned a:1;unsigned b:3;unsigned c:4;} bit,*pbit;bit.a=1; /* 给位域赋值(应注意赋值不能超过该位域的允许范围) */bit.b=7; /* 给位域赋值(应注意赋值不能超过该位域的允许范围) */bit.c=15; /* 给位域赋值(应注意赋值不能超过该位域的允许范围) */printf("%d,%d,%d\n",bit.a,bit.b,bit.c); /* 以整型量格式输出三个域的内容 */pbit=&bit; /* 把位域变量 bit 的地址送给指针变量 pbit */pbit->a=0; /* 用指针方式给位域 a 重新赋值,赋为 0 */pbit->b&=3; /* 使用了复合的位运算符 "&=",相当于:pbit->b=pbit->b&3,位域 b 中原有值为 7,与 3 作按位与运算的结果为 3(111&011=011,十进制值为 3) */pbit->c|=1; /* 使用了复合位运算符"|=",相当于:pbit->c=pbit->c|1,其结果为 15 */printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c); /* 用指针方式输出了这三个域的值 */
}
上例程序中定义了位域结构 bs,三个位域为 a、b、c。说明了 bs 类型的变量 bit 和指向 bs 类型的指针变量 pbit。这表示位域也是可以使用指针的。
相关文章:
C语言 位域
C 语言的位域(bit-field)是一种特殊的结构体成员,允许我们按位对成员进行定义,指定其占用的位数。 如果程序的结构中包含多个开关的变量,即变量值为 TRUE/FALSE,如下: struct {unsigned int w…...
【LeetCode热题100】【技巧】颜色分类
题目链接:75. 颜色分类 - 力扣(LeetCode) 只需排序三种,可以记录0和1的个数,然后直接原地赋值 class Solution { public:void sortColors(vector<int> &nums) {int zero 0, one 0;for (auto &num: n…...

笔记本电脑win7 Wireless-AC 7265连不上wifi6
1.背景介绍 旧路由器连接人数有限,老旧,信号不稳定更换了新路由器,如 TL-XDR5430易展版用户电脑连不上新的WIFI网络了,比较着急 核心问题:有效解决笔记本连接wifi上网问题,方法不限 2.环境信息 Windows…...

Linux gcc day5粘滞位
粘滞位 背景:一定时在一个公共目录(root创建)下。进行临时文件的操作 Linux系统中有很多人,我们需要在一个公共目录下,进行临时文件的操作(增删查改) 创建一个根目录下的dir(mytmp…...

单片机按键消抖常用的软硬件方法
一:什么是开关抖动? 当我们按下按钮或拨动开关或微动开关时,两个金属部件会接触以短路电源。但它们不会立即连接,而是金属部件在实际稳定连接之前连接和断开几次。释放按钮时也会发生同样的事情。这会导致误触发或多次触发&#…...
钉钉自建应用-下载excel(h5)
由于不同手机对于文件下载有不同的支持,而且文件路径也不一样,找起来十分的麻烦。所以,最好是找到一个都支持的方法。还好,钉钉官网提供了网盘,我们可把文件保存到钉钉自带的网盘,这样方便查找。 这里需要…...

用二八定律分析零售数据,不就更直观了吗?
20%的商品贡献了80%的销售金额,你会不会想知道这些商品的销售金额、毛利、销售金额累计占比、毛利累计占比,会不会想知道这些商品在各个门店的销售表现?看是否能进一步提高销售金额,提高毛利。这样的报表该怎么做?奥威…...

NetSuite Saved Search-当前库存快照查询报表(二)
之前第一篇文章我们说明了,如何利用Saved Search来制作一个能够显示批次物料与非批次物料的Lot信息以及On Hand在手数量的“当前库存快照查询报表”,但是当用户提出“我们能否再加上批次物料的效期”需求时,我们原有的Saved Search并不能达到…...

【JavaSE】接口 详解(上)
前言 本篇会讲到Java中接口内容,概念和注意点可能比较多,需要耐心多看几遍,我尽可能的使用经典的例子帮助大家理解~ 欢迎关注个人主页:逸狼 创造不易,可以点点赞吗~ 如有错误,欢迎指出~ 目录 前言 接口 语法…...

嵌入式C基础——循环队列 ringbuffer 讲解
本期主题: 讲解ARRAY_SIZE的作用以及定义,还有一个踩坑分析 往期链接: 数据结构系列——先进先出队列queue数据结构系列——栈 stackLinux内核链表零长度数组的使用inline的作用嵌入式C基础——ARRAY_SIZE使用以及踩坑分析 目录 1. Ringbuff…...

【动态规划-状态压缩dp】【蓝桥杯备考训练】:毕业旅行问题、蒙德里安的梦想、最短Hamilton路径、国际象棋、小国王【已更新完成】
目录 1、毕业旅行问题(今日头条2019笔试题) 2、蒙德里安的梦想(算法竞赛进阶指南) 3、最短Hamilton路径(《算法竞赛进阶指南》&模板) 4、国际象棋(第十二届蓝桥杯省赛第二场C A组/B组&#…...

全坚固笔记本丨工业笔记本丨三防笔记本相较于普通笔记本有哪些优势?
三防笔记本和普通笔记本在设计和性能方面存在显著差异,三防笔记本相较于普通笔记本具备以下优势: 三防笔记本通常采用耐磨、耐摔的材料,并具有坚固的外壳设计,能够承受恶劣环境和意外碰撞,有效保护内部组件不受损坏。相…...
机房搬迁方案
一、项目背景 随着XX公司业务的不断扩展,现有的机房设备已经无法满足日益增长的数据处理需求。同时,考虑到现有机房的设施老化及潜在的安全隐患,XX公司决定进行机房搬迁。本次搬迁旨在确保业务连续性、数据安全性以及新机房的高效运营。 二…...

推动科技创新润德生物邀您到场参观2024第13届生物发酵展
参展企业介绍 山东润德生物科技有限公司成立于2014年10月17日,是一家围绕生物制品的研发、生产、营销、国际贸易、技术服务为核心业务的国家高新技术企业,近年来荣获国家制造业单项冠军示范企业、国家级绿色工厂、国家知识产权优势企业、国家工业产品绿…...
如何在JavaScript中提高性能
在JavaScript中提高性能是一个涉及多个方面的任务,包括代码优化、数据结构选择、异步编程、避免全局查找、内存管理等。以下是一些关键的策略和技巧,可以帮助你提高JavaScript代码的性能: 1. 优化循环 使用for循环代替forEach,特…...
外观模式(面子模式)
外观模式 文章目录 外观模式什么是外观模式示例 什么是外观模式 外观模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用 Facade 外观类 知道哪些子系统类负责处理请求,将客…...

蓝桥杯考前复习三
1.约数个数 由乘法原理可以得出: import java.util.*; public class Main{static int mod (int)1e9 7;public static void main(String[] args){Map<Integer,Integer> map new HashMap<>(); //创建一个哈希表Scanner scan new Scanner(System.in);i…...

极客时间: 用 Word2Vec, LangChain, Gemma 模拟全本地检索增强生成(RAG)
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
VBA操作Word
检查word中的字体情况 Sub ListAllFontsInDocument()Dim doc As DocumentDim rng As RangeDim char As RangeDim fontName As StringDim uniqueFonts As Collection 初始化集合用于存储唯一字体名称Set uniqueFonts New Collection 获取当前活动文档Set doc ActiveDocument …...

Linux文件IO(4):目录操作和文件属性获取
目录 1. 前言 2. 函数介绍 2.1 访问目录 – opendir 2.2 访问目录 – readdir 2.3 访问目录 – closedir 2.4 修改文件访问权限 – chmod/fchmod 2.5 获取文件属性 – stat/lstat/fstat 2.5.1 文件属性 – struct stat 2.6 文件类型 – st_mode 3. 代码练习 3.1 要求 3.2 代…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...

MyBatis中关于缓存的理解
MyBatis缓存 MyBatis系统当中默认定义两级缓存:一级缓存、二级缓存 默认情况下,只有一级缓存开启(sqlSession级别的缓存)二级缓存需要手动开启配置,需要局域namespace级别的缓存 一级缓存(本地缓存&#…...

《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...