由浅到深认识C语言(12):位段/位域

2024-03-17 11:12
文章标签 语言 认识 位域 位段

本文主要是介绍由浅到深认识C语言(12):位段/位域,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

该文章Github地址:https://github.com/AntonyCheng/c-notes

在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址:https://blog.csdn.net/AntonyCheng/article/details/136555245),该模板集成了最常见的开发组件,同时基于修改配置文件实现组件的装载,除了这些,模板中还有非常丰富的整合示例,同时单体架构也非常适合SpringBoot框架入门,如果觉得有意义或者有帮助,欢迎Star & Issues & PR!

上一章:由浅到深认识C语言(11):结构体

12.位段/位域

这里需要记住,在内存中数据插入输出的顺序,即逆序插入,顺序输出!详解在8.3指针变量中变量的类型;

问题提出:信息在计算机的存取长度一般以 Byte 为单位,但是有时候存储一个信息不必用到一个或者多个 Byte,例如”真“或”假“用 1 或 0 表示即可,只需要 1 bit,此时我们就需要使用位段

**定义:**C语言允许在一个结构体中以 bit 为单位来指定其成员所占内存长度,以 bit 为单位的成员称为”位段“或称”位域“,而且这些成员的数据类型大都为 unsigned int ,也可以用 unsigned char

格式示例如下:

struct data
{unsigned int a : 2;		//a占2位unsigned int b : 6;		//b占6位unsigned int c : 4;		//c占4位unsigned int d : 4;		//d占4位unsigned int i;			//i占32位
}data;

图解如下:

idcba
32bit4bit4bit6bit2bit

而且相邻位域是可以被压缩的,且相邻位域压缩的位数不能超过成员自身的大小;

解释如下: 以下数据类型仅为 unsigned int 和 unsigned char;

若相邻成员数据类型相同(可压缩):

  • 如果我们使用的是 unsigned int 类型,最多能够压缩 32 个连续的 unsigned int num : 1; 即最多压缩 320/1 编码,如果连续的相同数据类型成员位数超过了 4B ,即 32b ,如果大小溢出了 4B ,即大于等于了 33b 的话,进而成为 8B ,如果只压缩了 33unsigned int num : 1 ,无论打印出来是多少 B ,实际大小还是为 33b ,往后以此类推;

  • 如果我们使用的是 unsigned char 类型,最多能够压缩 8 个连续的 unsigned char ch : 1; 即最多压缩 80/1 编码,如果连续的相同数据类型成员位数超过了 1B ,即 8b ,如果大小溢出了 1B ,即大于等于了 9b 的话,进而成为 2B ,如果只压缩了 9unsigned char ch : 1 ,无论打印出来是多少 B ,实际大小还是为 9b ,往后以此类推;

若相邻成员数据类型不同(不可压缩):

不相邻的两个成员或者两类成员,则既要将两类数据内存按照 int 或者 char 基本数据类型的内存进行加减,又要将每一类中的各个成员内存进行压缩;

示例如下:

#include<stdio.h>
#pragma pack(1)
struct bit_data
{unsigned char a : 1;unsigned char b : 1;unsigned char c : 1;unsigned char d : 1;unsigned char e : 1;unsigned char f : 1;unsigned char g : 1;unsigned char h : 1;
}data;int main(int argc, char* argv[]) {printf("data = %d\n", sizeof(data));
}

打印效果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

12.1.位段的注意事项

  • 位段不能取地址:

    因为内存地址是以 Byte 为单位,因为系统内存是以 Byte 为基本单位,系统不会识别在 bit 上的地址;

  • 位段的赋值:

    不要操作越界的数据,解释如下:

    #include<stdio.h>struct bit_data
    {unsigned char a : 1;	//0-1				==>		0-1unsigned char b : 2;	//00-11				==>		0-3unsigned char c : 3;	//000-111			==>		0-7unsigned char d : 4;	//0000-1111			==>		0-15unsigned char e : 5;	//00000-11111		==>		0-31unsigned char f : 6;	//000000-111111		==>		0-63unsigned char g : 7;	//0000000-1111111	==>		0-127unsigned char h : 8;	//00000000-11111111	==>		0-255
    }data;int main(int argc, char* argv[]) {data.a = 1;printf("%u\n", data.a);data.b = 3;printf("%u\n", data.b);data.c = 7;printf("%u\n", data.c);data.d = 15;printf("%u\n", data.d);data.e = 31;printf("%u\n", data.e);data.f = 63;printf("%u\n", data.f);data.g = 127;printf("%u\n", data.g);data.h = 255;printf("%u\n", data.h);
    }
    

    打印效果如下:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 无意义位段:

    无意义位段用来限制压缩,解释如下:

    以下示例将位段定义成了全局变量,可以不用初始化为零值(因为全局变量会自动初始化),但是如果将该位段定义成局部变量,那么就需要我们手动初始化为零,因为局部变量载入时是一个不确定的值;

    struct bit_data
    {unsigned char a : 2;unsigned char : 2;    //无意义的位段,仅作占位符,占两个 bitunsigned char b : 2;unsigned char c : 2;
    }data;
    

    图示如下:

    ccbbaa

    验证如下:

    #include<stdio.h>
    #include<string.h>
    struct bit_data
    {unsigned char a : 2;unsigned char : 2;    //无意义的位段,仅作占位符,占两个 bitunsigned char b : 2;unsigned char c : 2;
    }data;int main(int argc, char* argv[]) {//如果是定义成了局部变量,还需要包含string.h头文件,然后://memset(&data,0,1);data.a = 0;data.b = 2;data.c = 3;//此时data转换成二进制为 1110 0000 ==> 十六进制 0xe0printf("data = %#x\n",data);
    }
    

    打印效果如下:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 另起一个位段:

    当我们将无意义位段设置为 0 时,我们就成功另起了一个位段,即在内存的另一处重新开辟了一个容器来装下一个位段的内容,证明如下:

    #include<stdio.h>
    #include<string.h>
    typedef struct data{unsigned char a : 2;unsigned char : 0;unsigned char b : 2;unsigned char : 0;unsigned char c : 2;unsigned char : 0;unsigned char d : 2;
    }DATA;int main(int argc, char* argv[]) {DATA data;memset(&data, 0, 4);//此时这个结构体里包含了四个位段地址printf("sizeof(data) = %d\n", sizeof(data));data.a = 0;data.b = 1;data.c = 2;data.d = 3;printf("%x\n", data);
    }
    

    打印效果如下:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

12.2.位域和单片机

图解如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码如下:

#include<stdio.h>typedef struct {unsigned char data : 1;unsigned char : 1;unsigned char addr : 2;unsigned char : 1;unsigned char opt : 2;unsigned char : 1;
}DATA;int main(int argc, char* argv[]) {//下面是单片机定义DATA msg;msg.data = 1;msg.addr = 2;msg.opt = 1;
}

上一章:由浅到深认识C语言(13):共用体

这篇关于由浅到深认识C语言(12):位段/位域的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/818779

相关文章

C语言中的数据类型强制转换

《C语言中的数据类型强制转换》:本文主要介绍C语言中的数据类型强制转换方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C语言数据类型强制转换自动转换强制转换类型总结C语言数据类型强制转换强制类型转换:是通过类型转换运算来实现的,主要的数据类型转换分为自动转换

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

C语言实现两个变量值交换的三种方式

《C语言实现两个变量值交换的三种方式》两个变量值的交换是编程中最常见的问题之一,以下将介绍三种变量的交换方式,其中第一种方式是最常用也是最实用的,后两种方式一般只在特殊限制下使用,需要的朋友可以参考下... 目录1.使用临时变量(推荐)2.相加和相减的方式(值较大时可能丢失数据)3.按位异或运算1.使用临时

使用C语言实现交换整数的奇数位和偶数位

《使用C语言实现交换整数的奇数位和偶数位》在C语言中,要交换一个整数的二进制位中的奇数位和偶数位,重点需要理解位操作,当我们谈论二进制位的奇数位和偶数位时,我们是指从右到左数的位置,本文给大家介绍了使... 目录一、问题描述二、解决思路三、函数实现四、宏实现五、总结一、问题描述使用C语言代码实现:将一个整

C语言字符函数和字符串函数示例详解

《C语言字符函数和字符串函数示例详解》本文详细介绍了C语言中字符分类函数、字符转换函数及字符串操作函数的使用方法,并通过示例代码展示了如何实现这些功能,通过这些内容,读者可以深入理解并掌握C语言中的字... 目录一、字符分类函数二、字符转换函数三、strlen的使用和模拟实现3.1strlen函数3.2st

Go语言中最便捷的http请求包resty的使用详解

《Go语言中最便捷的http请求包resty的使用详解》go语言虽然自身就有net/http包,但是说实话用起来没那么好用,resty包是go语言中一个非常受欢迎的http请求处理包,下面我们一起来学... 目录安装一、一个简单的get二、带查询参数三、设置请求头、body四、设置表单数据五、处理响应六、超

C语言中的浮点数存储详解

《C语言中的浮点数存储详解》:本文主要介绍C语言中的浮点数存储详解,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、首先明确一个概念2、接下来,讲解C语言中浮点型数存储的规则2.1、可以将上述公式分为两部分来看2.2、问:十进制小数0.5该如何存储?2.3 浮点

基于Python实现多语言朗读与单词选择测验

《基于Python实现多语言朗读与单词选择测验》在数字化教育日益普及的今天,开发一款能够支持多语言朗读和单词选择测验的程序,对于语言学习者来说无疑是一个巨大的福音,下面我们就来用Python实现一个这... 目录一、项目概述二、环境准备三、实现朗读功能四、实现单词选择测验五、创建图形用户界面六、运行程序七、

使用Go语言开发一个命令行文件管理工具

《使用Go语言开发一个命令行文件管理工具》这篇文章主要为大家详细介绍了如何使用Go语言开发一款命令行文件管理工具,支持批量重命名,删除,创建,移动文件,需要的小伙伴可以了解下... 目录一、工具功能一览二、核心代码解析1. 主程序结构2. 批量重命名3. 批量删除4. 创建文件/目录5. 批量移动三、如何安

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本