C语言基础知识:位与位字段
目录
位与字节
位
比特
字节
对齐特性
位字段
位与字节
位
二进制数系统中,每个0或1就是一个位(bit),位是数据存储的最小单位。其中8 bit就称为一个字节(Byte)。计算机中的CPU位数指的是CPU一次能处理的最大位数,例如32位计算机的CPU一次最多能处理32位数据,计算机中的CPU位数也成为机器字长,和数据总线(CPU与内部存储器之间连接的用于传输数据的线的根数)的概念是统一的。
比特
1) 计算机专业术语,是信息量单位,是由英文BIT音译而来。二进制数的一位所包含的信息就是一比特,如二进制数0101就是4比特。
2)二进制数字中的位,信息量的度量单位,为信息量的最小单位。数字化音响中用电脉冲表达音频信号,“1”代表有脉冲,“0”代表脉冲间隔。如果波形上每个点的信息用四位一组的代码表示,则称4比特,比特数越高,表达模拟信号就越精确,对音频信号信号还原能力越强。
字节
1字节(byte) = 8 比特(bit)
注:这个字节与比特的关系是规定的,记住就好,通用于任何场景,容易混淆的是字长和字节,字长指的是cpu一次性能够运算的数据的位数,不同的计算机可能不一样,但是字节这个概念是恒久不变的。
对齐特性
对齐指的是如何安排对象在内存中的位置。
_Alignof运算符给出了一个类型的对齐要求,在关键字_Aligof后面的圆括号中写上类型名即可:
size_t d_align = _Alignof(float);
假定d_align的值是4,意思float类型对象的对齐要求是4。较大的对齐值被称为stricter或stronger,较小的值被称为weaker.
可以使用_Alignas说明符指定一个变量或类型的对齐值,但是不应该要求该值小于基本对齐值。
_Alignas(double) char c1;
_Alignas(8) char c2;
unsigned char _Alignas(long double) c_arr[sizeof(long double)];
注意:
位字段
位字段(bit filed)是C语言中一种存储结构,不同于一般结构体的是它在定义成员的时候需要指定成员所占的位数。位字段是一个signed int或unsigned int类型变量中一组相邻的位(C99和C11新增了Bool类型的位字段)。位字段通过一个结构声明来建立,该结构声明为每个字段提供标签,并确定该字段的宽度。例如,下面的声明建立了4个1位的字段:
struct {unsigned autfd : 1;unsigned bldfc : 1;unsigned undln : 1;unsigned itals : 1;
} prnt;
根据该声明,prnt包含了4个1位的字段。现在,可以通过普通的结构成员运算符(.)单独给这些字段赋值:
prnt.itals=1;prnt.undln=0;prnt.bldfc=1;prnt.autfd=0;
下面查看一下prnt的值:
char str[33];int* value=reinterpret_cast<int*>(&prnt);itoa(*value,str,2);printf("%d %d %d %d\n", prnt.autfd,prnt.bldfc,prnt.undln,prnt.itals);printf("sizeof(prnt) = %d\n",sizeof(prnt));printf("十进制: %d\n",prnt);printf("二进制: %032s\n",str);
输出的结果为:
0 1 0 1
sizeof(prnt) = 4
十进制: 10
二进制: 0000 0000 0000 0000 0000 0000 0000 1010
可以看出,prnt的大小为4个字节(unsigned int 或 signed int),通过prnt的结构成员可以设置和访问某些bit位的值。
带有位字段的结构提供了一种记录设置的方便途径。许多设置(如,字体的粗体或斜体)就是简单的二进制一。例如,开或关、真或假。如果只需要使用1位,就不需要使用整个变量。内含位字段的结构允许在一个存储单元中存储多个设置。
有时,某些设置也有多个选择,因此需要多位来表示。例如,可以使用如下代码:
struct{unsigned code1 : 2;unsigned code2 : 2;unsigned code3 : 8;
}prcode;
这里创建了两个2位的字段和一个8位的字段,可以这样赋值:
prcode.code1=0;prcode.code2=3;prcode.code3=102;
但是要确保赋的值不超出字段可容纳的范围(下面会说明当超出范围时会发生什么事情)。
再次打印出prcode的内容
int* value_prcode=reinterpret_cast<int*>(&prcode);itoa(*value_prcode,str,2);printf("%d %d %d\n",prcode.code1,prcode.code2,prcode.code3);printf("sizeof(prcode) = %d\n",sizeof(prcode));printf("十进制: %d\n",prcode);printf("二进制: %032s\n",str);
打印结果如下:
0 3 102
sizeof(prcode) = 4
十进制:1644
二进制:0000 0000 0000 0000 0000 0110 0110 1100
可以看出,prcode.code1对应于0-1比特位,数值为00,对应十进制为0;
prcode.code1对应于2-3比特位,数值为11,对应十进制为3;
prcode.code2对应于4-11比特位,数值为0110 0110,对应十进制为102。
因此,一个字段可以对应于多个比特位,且当使用结构字段赋值在可容纳的范围之内时,变量可以记录正确的值。
这里再讨论一些需要注意的问题。首先是,如果声明的总位数超过一个unsigned int类型的大小(4 bytes)时会发生什么事情?结果是会用到下一个unsigned int类型的存储位置。一个字段不允许跨越两个unsigned int之间的边界。编译器会自动移动跨界的字段,保持unsigned int的边界对齐。一旦发生这种情况,第1个unsigned int中会留下一个未命名的“洞”。例如:
struct{unsigned a : 4;unsigned b : 4;unsigned c : 4;unsigned d : 25;
}prlimit;
上面定义的位字段大小共37个bits,超过了一个unsigned int的范围,给prlimit的各结构成员赋值,并使用下面代码打印出prlimit所存储的内容:
prlimit.a=0xF;prlimit.b=0;prlimit.c=0xF;prlimit.d=0x1FFFFFF;char str_1[33];char str_2[33];int* value_1=reinterpret_cast<int*>(&prlimit);int* value_2=reinterpret_cast<int*>(&prlimit)+1;itoa(*value_1,str_1,2);itoa(*value_2,str_2,2);printf("0x%x 0x%x 0x%x 0x%x \n",prlimit.a,prlimit.b,prlimit.c ,prlimit.d);printf("sizeof(prlimit) = %d\n",sizeof(prlimit));printf("二进制 0~31位: %032s\n",str_1);printf("二进制 32~63位: %032s\n",str_2);
输出的结果如下:
0xf 0x0 0xf 0x1ffffff
sizeof(prlimit) = 8
二进制 0-31位:0000 0000 0000 0000 0000 1111 0000 1111
二进制 32-63位:0000 0001 1111 1111 1111 1111 1111 1111
从输出的结果可以看出,首先,prlimit的大小为8个字节;其次,编译器强制prlimit.d字段发生边界对齐,即prlimit.d位于第二个unsigned int上,prlimit.c与prlimit.d之间会填充未命名的“洞”。
实际上,我们也可以人为的在结构体当中设置未命名的字段宽度来进行填充。使用一个宽度为0的未命名的字段迫使下一个字段与下一个整数对齐:
struct {unsigned field1 : 1;unsigned : 2;unsigned field2 : 1;unsigned : 0;unsigned field3 : 4;
} stuff;
使用下面的代码输出stuff的内容:
stuff.field1=1;stuff.field2=1;stuff.field3=0xf;char str_1[33];char str_2[33];int *value_1=reinterpret_cast<int*>(&stuff);int *value_2=reinterpret_cast<int*>(&stuff)+1;itoa(*value_1,str_1,2);itoa(*value_2,str_2,2);printf("sizeof(stuff) = %d\n",sizeof(stuff));printf("二进制 0-31位: %032s\n",str_1);printf("二进制 32-63位: %032s\n",str_2);
输出的结果为:
sizeof(stuff) = 8
二进制 0-31位:0000 0000 0000 0000 0000 0000 0000 1001
二进制 32-63位: 0000 0000 0000 0000 0000 0000 0000 1111
也就是说,在这里,stuff.field1和stuff.field2之间,有一个2位的空隙;stuff.field3被强迫与下一个整数对齐,存储到下一个unsigned int中。stuff的大小为8个字节。
最后讨论一个当赋值超出字段可容纳范围的问题。
struct {unsigned t1 : 2;unsigned t2 : 3;unsigned t3 : 4;
} test;int main(){test.t1=3;test.t3=0;test.t2=11;printf("%d %d %d\n",test.t1,test.t2,test.t3);int *value=reinterpret_cast<int*>(&test);char str[50];itoa(*value,str,2);printf("二进制:%032s\n",str);return 0;}
输出的结果为:
3 3 0
二进制:0000 0000 0000 0000 0000 0000 0000 1111
上述代码中,成员test.t2赋值的大小超出了容纳的范围。可以看到,t2赋值为11(二进制是1011),结果输出的值是3(二进制是011),即截断了超出的部分。同时也可以看到,超出的部分不会影响t3的值(不同平台不一样?网上有人说会覆盖超出的区域)。
最后需要说明的是,字段存储在一个int中的顺序取决于机器。在有些机器上,存储的顺序是从左往右的,而在另一些机器上,是从右往左的。另外,不同的机器中两个字段边界的位置也有区别。由于这些原因,位字段通常都不容易移植。尽管如此,有些情况却要用到这种不可移植的特性。例如,以特定硬件设备所用的形式存储数据。
相关文章:
C语言基础知识:位与位字段
目录 位与字节 位 比特 字节 对齐特性 位字段 位与字节 位 二进制数系统中,每个0或1就是一个位(bit),位是数据存储的最小单位。其中8 bit就称为一个字节(Byte)。计算机中的CPU位数指的是CPU一次能处理的最大位数࿰…...

新版android studio gradle插件7.4.2.pom一直无法下载问题
android studio同步时候出现org.gradle.api.plugins.UnknownPluginException,Plugin [id: com.android.application, version: 7.4.2] was not found in any of the following sources: pom插件一直无法下载,搞了好几天,简直想砸电脑&#x…...
Shell——变量和引用
1.总结变量的类型及含义? 2.实现课堂案例计算长方形面积?(6种方式) 3.定义变量urlhttps://blog.csdn.net/weixin_45029822/article/details/103568815 (通过多种方法实现) 1)截取网站访问的协…...

实际开发中一些实用的JS数据处理方法
写在开头 JavaScript 是一种脚本语言,最初是为了网页提供交互式前端功能而设计的,而现在,通过 Node.js,JavaScript 还可以用于编写服务器端代码。 JavaScript 具有动态性、基于原型的面向对象特性、弱类型、多范式、支持闭包执行…...

10:00进去,10:05就出来了,这问的也太变态了···
从外包出来,没想到死在另一家厂子了。 自从加入这家公司,每天都在加班,钱倒是给的不少,所以也就忍了。没想到5月一纸通知,所有人不许加班,薪资直降30%,顿时有吃不起饭的赶脚。 好在有个兄弟内推…...

GPT时代,最令人担心的其实是“塔斯马尼亚效应”
目录 教育到底教什么? 过度依赖GPT可能导致文明退化 GPT可以帮助人类破解“学海无涯极限”悖论 春季学期伊始,全球各地的老师们如临大敌,因为学生们带着ChatGPT杀过来了。Study.com的调研显示,每10个学生中就有超过9个知道Chat…...
基于容器技术和服务发现的全新大数据平台弹性伸缩方法
随着科技的不断发展,各个行业都在不断地数字化和智能化。在这个过程中,大数据技术成为了许多行业的重要支撑。而随着大数据技术的普及,行业分类和设备装置的不断更新换代,弹性伸缩成为了一个不可避免的问题。本文将介绍基于服务发…...
php8 match
刚从 php7 升级到 php8 时 我在使用 switch 语句,结果出现了一个提示: "switch statement can be converted to match expression" 翻译过来就是: switch语句可以转换为match表达式 我当时在想,match 应该是php8 的…...

ADS-B接收机Radarcape
1.设备简介 Radarcape是一款便携、高性能、功能强大的ADS-B地面接收机。Radarcape的设备清单包含:ADS-B接收机主机,专业级ADS-B天线,GPS天线,电源线,网线。 2. 功能特点 Radarcape可以通过网口输出飞机的原始数据D…...
软件测评师2012年下半年考试真题<更新中。。。>
1.2012 年下半年全国计算机技术与软件专业技术资格(水平)考试日期是 11月4号。 2.在 CPU 中,控制器 不仅要保证指令的正确执行,还要能够处理异常事件。 3.循环冗余校验码(CRC) 利用生成多项式进行编码。设数据位为 k 位…...

ChatGPT 使用 拓展资料:开始构建你的优质Prompt
ChatGPT 使用 拓展资料:开始构建你的优质Prompt...

Hystrix原理
一.概述 在软件架构领域,容错特指容忍并防范局部错误,不让这种局部错误不断扩大。我们在识别风险领域,风险可以分为已知风险和未知风险,容错直接应对的就是已知风险,这就要求针对的场景是:系统之间调用延时…...

内网外网分离模式下,通过网关转发,来部署前后端分离的系统
前言 最近为某银行系统部署了一套商城系统,网络环境比较特别,思路记录下,其中商场系统使用前后端分离模式部署。 该银行网络环境: 外网服务器:外网可以访问到它,不能访问外网。 网关服务器:跟…...

基于 Amazon API Gatewy 的跨账号跨网络的私有 API 集成
一、背景介绍 本文主要讨论的问题是在使用 Amazon API Gateway,通过 Private Integration、Private API 来完成私有网络环境下的跨账号或跨网络的 API 集成。API 管理平台会被设计在单独的账号中(亚马逊云科技提供的是多租户的环境),因为客观上不同业务…...
SSH远程连接时报错kex_exchange_identification: Connection closed by remote host
简介 在SSH服务器上进行远程内容时,会经常出现kex_exchange_identification: Connection closed by remote host内容,主要是由于远程计算机登录节点的数量限制问题。 解释 在 SSH 服务器上,最大并发登录会话数是由 ‘MaxSessions’ 参数来…...

一、CNNs网络架构-基础网络架构
目录 1.LeNet 2.AlexNet 2.1 激活函数:ReLU 2.2 随机失活:Droupout 2.3 数据扩充:Data augmentation 2.4 局部响应归一化:LRN 2.5 多GPU训练 2.6 论文 3.ZFNet 3.1 网络架构 3.2 反卷积 3.3 卷积可视化 3.4 ZFNet改…...
[开发|C++] C++的基本运算符说明笔记
基本运算符说明 C是一种功能强大的编程语言,提供了多种运算符来执行各种基本操作。下面是一些常见的C基本运算符及其说明: 算术运算符: :加法运算符,用于执行两个操作数的相加操作。 -:减法运算符…...
抖音定位功能的作用
随着智能手机和社交网络的普及,人们日常生活中对于位置信息的需求也越来越高。而抖音作为一款以短视频为主的社交应用,其定位技术也备受关注。本文将就抖音的定位功能进行探究,介绍抖音如何获取、处理和利用用户的位置信息,并探讨…...

阿里 P9 推荐的 Spring 领域巅峰之作,直接颠覆了我对 Spring 的认知
写在前面 你第一次接触 spring 框架是在什么时候?相信很多人和我一样,第一次了解 spring 都不是做项目的时候用到,而是在网上看到或者是听到过一个叫做 spring 的框架,这个框架号称完爆之前的 structs 和 structs2,吸…...

R语言结构方程模型(SEM)在生态学领域中的实践应用
结构方程模型(Sructural Equation Model)是一种建立、估计和检验研究系统中多变量间因果关系的模型方法,它可以替代多元回归、因子分析、协方差分析等方法,利用图形化模型方式清晰展示研究系统中变量间的因果网络关系,…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...