C语言基础:掩码运算(位运算)

news2024/10/4 6:39:10

前言

        以前写过一篇流水灯的帖子单片机C51之1:流水灯_小灯连续亮灭程序是什么-CSDN博客,里面用到了位运算,当时写代码的思路还不是很清晰,对位运算用得不是很熟练,笔者最近在看的<深入理解计算机系统>(以下称"本书")里也提到了位运算,所以对此做一个较为完整的用法的归纳

引入

        C语言和C++是偏向底层的语言,用起来肯定不如Java之类"纯面向对象"的语言那么舒服,但也正是因为其偏底层,对喜欢探索计算机底层的人来说,会比较有趣.

移位运算基础

        数据在内存中以字节为单位存在.先简单理解下移位运算的规则:

        假设有一个数据:int a=0B10101101;       

        注:二进制比较容易说明,相当于十六进制的0xad;十进制的173.

        1>数据左移:移出位丢弃,补0;

        a=a<<4;                    //左移4位

        结果:0B11010000;   

#include<stdlib.h>
#include<stdio.h>

int main(void) {
	unsigned char a = 0B10101101;		//无符号八位整数
	a=a << 4;							//左移4位
	printf("%d\n", a);		            //a值等于0B11010000			
	printf("%d", 0B11010000);			//打印结果同上
}

        因为在C语言中,没有专门的二进制数据类型,所以用了unsigned char(0~127)这个类型表示八位二进制数0B10101101,左移四位结果是没有问题的.如果用int或者其他整型接收原始数据,得出的结果虽然用十进制表示不一样,但移位的结果是相同的,可以验证

        2>数据右移,移出位丢弃

        本书上说大部分编译器都是补最左端数,本例中为1,即结果应为0B11111101但vs2019打印出来是补0.

	a = a >> 4;							//右移4位
	printf("%d\n", a);					//打印成十进制
	printf("0x%x\n", a);				//打印成十六进制

        结果是13,由上一步的a值0B11010000移位得来,运算后的a值是0B00001101(十六进制0xd),如果在某个编程环境下打印出来结果是0B11111101,十进制253,十六进制0xfd,也不用奇怪,那是右移补最左端数的规则

        关于这一点不用纠结,因为在移位运算中只用左移就可以了,不用担心出错.

置位运算

        置位简单来说就是设为"1"(true),为何要叫做运算呢?因为他能适应更多的情况,让代码变得简单.用一种"移位或"的方法来置位.

        举例:假设有一个数据0B11000000,要将其第4位设为1.写法如下:

	unsigned char b = 0B11000000;
	b = b |1<< 4;                       //移位或
	printf("%d\n", b);					//结果208,二进制0B11010000,移位成功

        不论原始数据第4位是否为1,经移位或运算以后,已被设置为1.

        注意:移位运算是从第0位算起,所以移4位,从左数起是第5个数字.

复位运算

        复位运算与置位运算相反,是设为"0",用一种"移位与"(移位取反与)的方法实现.

        假设将前面的b(0B11010000)第4位复位为0,写法如下:

	unsigned char tmp = 1 << 4;			//复位运算,建立临时数据tmp;
	b = b & ~tmp;						//取反与
	printf("%d\n", b);					//结果192,二进制0B11000000

        复位的思路:将某个位复位为0(比如第n个)→和这个数据(b)相与:0B111110111(数据中的0处于第n位)→b的计算:先移位或----1<<n再将其取反.

        复位用了一个位运算的特点:和1相与,原值不变;同样置位运算也用了一个特点:和0相或,原值不变.所以上述代码有个好处是:除了修改目标位,其他位不受影响.

多个位的置位和复位

        上面的例子演示了把第4位置位和复位,如果一次要多个置位或复位呢?也比较简单,只要在代码上用相同的方法添加就行了.比如同时置位和复位第4位和第5位

        置位4,5两个位

	unsigned char b = 0B11000000;
	b = b |1<< 4;                       //移位或第4位
    b = b |1<< 5;                       //移位或第5位
	printf("%d\n", b);					

        复位4,6两个位

	unsigned char tmp = 1 << 4;			//复位运算,建立临时数据tmp;
    tmp = tmp | 1 << 5;                 //移位或第5位
	b = b & ~tmp;						//取反与
	printf("%d\n", b);					

==========================内容分割线=======================================

        有必要说一下可能的疑问:为什么推荐用运算的方式去设置位数据,可以"硬写"啊,当某情况出现的时候,把寄存器的值直接修改不就行了?是的,没错,直接改也是可以的.但考虑到如果寄存器不是8位的,如32位的,现在给你一张32位的表,注明了每个位在0和1时分别代表什么意思,用来写代码

        32位寄存器用十六进制表示:0x1234568(示例),如果是二进制数0B1111 1111 1111 1111 1111 1111 1111 1111,硬写时要么把目标数据换算成十六进制,要么需要数多少个0,位数多了容易出错.更不要说现在用64位编译器了.

==========================内容分割线====================================== 

切换位 

        好像还有个运算符^(异或)还没派上用场.只要是想用他,一定会用得着.

        先看位计算的一个特点:.

        0^0=0; 1^0=1;               //      和0异或仍为原值   

        0^1=1;  1^1=0;              //       和1异或切换原值 

        切换位的思路:切换(比如第n位)位→原始数据与这样的一个数(如tmp)进行异或运算:第n位为1,其他不需要切换的位为0→移位或做出tmp→反向写出代码

        举例:把0B11000000中第4和第5位切换,代码如下:

	/*切换位运算*/
	unsigned char tmp2 = 1 << 4;		//切换位运算,建立临时数据tmp2;
	tmp2 = tmp2 | 1 << 5;
	tmp2 = tmp2 | 1 << 7;
	b = b ^ tmp2;
	printf("%d\n", b);					//结果112,二进制0B01110000

小结 

        位运算的理解和应用.实现了置位,复位,切换位的功能.

         C++的写法和C语言在位控制上基本一致.

        个人感受:每天用面向对象考虑问题,偶尔写写C的代码,也算换换思路.

         后面会做一个和控制有关的实例.

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

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

相关文章

【硬件模块】HC-SR04超声波模块

HC-SR04超声波模块实物图 工作参数 探测距离&#xff1a;2~600cm 探测精度&#xff1a;0.1cm1% 感应角度&#xff1a;<15 输出方式&#xff1a;GPIO 工作电压&#xff1a;DC 3~5.5V 工作电流&#xff1a;5.3mA 工作温度&#xff1a;-40~85℃ 引脚接线 HC-SR04MCU备注VC…

Golang | Leetcode Golang题解之第454题四数相加II

题目&#xff1a; 题解&#xff1a; func fourSumCount(a, b, c, d []int) (ans int) {countAB : map[int]int{}for _, v : range a {for _, w : range b {countAB[vw]}}for _, v : range c {for _, w : range d {ans countAB[-v-w]}}return }

04-SpringBootWeb案例(下)

3. 员工管理 完成了部门管理的功能开发之后&#xff0c;我们进入到下一环节员工管理功能的开发。 基于以上原型&#xff0c;我们可以把员工管理功能分为&#xff1a; 分页查询&#xff08;今天完成&#xff09;带条件的分页查询&#xff08;今天完成&#xff09;删除员工&am…

Pikachu-Sql Inject-数字型注入(GET)

一、、破解 SQL 查询语句中的字段数 ?id1 order by 3 -- // -- 是注释&#xff0c; 加号 在MySQL中会转成空格 order by 1 &#xff0c;by 数字几&#xff0c;就是按照第几列进行排序&#xff1b;如果没有这一行&#xff0c;则报错 如&#xff1a;以下语句&#xff0c;根据…

QT学习笔记1(QT和QT creator介绍)

QT学习笔记1&#xff08;QT和QT creator介绍&#xff09; Qt 是一个跨平台的应用开发框架&#xff0c;主要用于图形用户界面&#xff08;GUI&#xff09;应用的开发&#xff0c;但也支持非GUI程序的开发。Qt 支持多种平台&#xff0c;如Windows、macOS、Linux、iOS和Android&a…

Servlet的生命周期及用户提交表单页面的实现(实验报告)

一、实验目的、要求 1. 掌握Servlet的定义&#xff0c;即Servlet是运行在服务器端的Java程序&#xff0c;用于扩展服务器的功能。 2. 学习和掌握在开发环境中搭建Servlet应用所需的工具&#xff0c;如Tomcat服务器、IDEA等。 二、实验内容 根据本章所学知识&#xff0c;实验…

linux第一课:下载与安装

这是我的个人复习笔记&#xff0c;草稿箱字太多会卡就发这了&#xff0c;欢迎大家阅读。 Kali Linux&#xff0c;黑客必备神器。跟着我&#xff0c;带你从入门到入狱&#xff01; 第一课&#xff0c;下载与安装。 第一步&#xff1a; 在官网下载Centos镜像&#xff1a;http…

(2025)408考研:王道操作系统文件管理强化

写在最前面,需要pdf的请资源里下载,已经排版好了,这里不知道为什么粘贴上来排版这么难看!!! 某一个分区进行格式化的时候,这个分区的文件系统就被建立了,一旦这个文件系统建立完后,就确定了文件系统使用的什么样的物理结构。 操作系统引导: 主存分为两部分,RAM和RO…

人体目标检测数据集 18000张 人体 带标注voc yolo

人体目标检测数据集 18000张 人体 带标注voc yolo 继续 人体目标检测数据集介绍 数据集名称 人体目标检测数据集 (Human Detection Dataset) 数据集概述 该数据集专为训练和评估基于YOLO系列目标检测模型&#xff08;包括YOLOv5、YOLOv6、YOLOv7等&#xff09;而设计&#…

vue-cli老项目继续优化:json压缩神器 compress-json

前言 上文讲到一个 vue-cli 带脚本生成内容的老项目的打包时间已经从 40min &#xff0c;优化到 12min &#xff0c;再到 9min 。 还有可以考虑的方式包含缩小脚本体积、依赖分包、构建的缓存等等。 那么本文就来讨论缩小脚本体积的方式。 分析 前文已知&#xff0c;生成的…

螺狮壳里做道场:老破机搭建的私人数据中心---Centos下Docker学习06(Docker网络连接)

如果要搭建基于docker的私人DC&#xff0c;除了虚拟机网络连接外&#xff0c;就得掌握docker的网络连接。磨刀不误砍柴工&#xff0c;或者说工欲善其事必先利其器&#xff0c;我们先学学典型的docker的网络连接方式。Docker的网络连接有四种&#xff1a;bridge、none、containe…

jmeter学习(2)变量

1&#xff09;用户定义的变量 路径&#xff1a;添加-》配置元件-》用户定义的变量 用户定义的变量是全局变量&#xff0c;可以跨线程组被调用&#xff0c;但在启动运行时获取一次值&#xff0c;在运行过程中不再动态获取值。 2&#xff09;用户参数 路径&#xff1a;…

扩展可持续性概念:太空移民、持久产品与人类未来

可持续性的扩展概念&#xff1a;超越绿色能源&#xff0c;关乎人类未来的延续 当我们听到“可持续性”这个词时&#xff0c;大多数人首先想到的是环境保护、绿色能源、减少碳足迹或保护生态系统。虽然这些都是不可忽视的重要部分&#xff0c;但可持续性远远超出了绿色能源的范…

RabbbitMQ篇(环境搭建 - 下载 安装)(持续更新迭代)

目录 一、Windows 1. 下载安装程序 2. 安装配置erlang 3. 安装rabbitMQ 4. 验证 二、Linux 1. 下载rpm包 1.1. 下载Erlang的rpm包 1.2. 下载socat的rpm包 1.3. 下载RabbitMQ的rpm包 2. 安装 2.1. 安装Erlang 2.2. 安装socat 2.3. 安装RabbitMQ 3. 启动RabbitMQ服…

酒店生态发展旅游四个一体化建设-—未来之窗行业应用跨平台架构

一、酒店在旅游中的作用 首先&#xff0c;酒店为游客提供了舒适的住宿环境。经过一天的游玩&#xff0c;游客需要一个干净、安全、设施齐全的空间休息&#xff0c;恢复精力&#xff0c;以更好地继续后续的行程。 其次&#xff0c;酒店是旅游服务的重要载体。它不仅提供住宿&am…

【Node.js】内置模块FileSystem的保姆级入门讲解

作者&#xff1a;CSDN-PleaSure乐事 欢迎大家阅读我的博客 希望大家喜欢 使用环境&#xff1a;Vscode 本文代码都经由博主PleaSure乐事实操后得出&#xff0c;可以放心使用。 1.FileSystem介绍 Node.js 的 fs&#xff08;filesystem&#xff09;模块是一个核心模块&#xff0c…

【MATLAB2024b】安装离线帮助文档(windows)

文章目录 一、在 MATLAB 设置中安装二、从math works 网站下载ISO&#xff1a;给无法联网的电脑安装 版本&#xff1a;matlab 2024b&#xff08;或者大于等于2023a&#xff09; 所需空间&#xff1a;10~15 GB 平台&#xff1a;Windows 需要注册math works账号。 一、在 MATLAB …

kubernets基础-ingress详细介绍

文章目录 什么是IngressIngress详细说明Ingress示例 Ingress控制器Ingress控制器的工作原理Ingress控制器的特点常见的Ingress控制器 Ingress关联Ingress控制器一、Ingress资源对象二、Ingress控制器三、Ingress与Ingress控制器的关联方式四、注意事项 多实例部署一、Ingress多…

《数据结构(刘大有)》学习(6)

系列文章目录 一、绪论 二、顺序表、链表 三、堆栈、队列 四、数组 五、字符串 六、树 目录 树的基本概念树的定义树的特点树的相关术语度层数高度路径二叉树定义特点定理满二叉树定义特点完全二叉树定义特点二叉树的存储结构顺序存储结点结构优点缺点 链式存储 结点结构…

带你深入浅出设计模式:四、原型模式:编程中的克隆技术

此为设计模式第四谈&#xff01; 用总-分-总的结构和生活化的例子给你讲解设计模式&#xff01; 码农不易&#xff0c;各位学者学到东西请点赞收藏支持支持&#xff01; 开始部分&#xff1a; 总&#xff1a;原型模式的核心逻辑在于通过克隆现有实例来创建新对象&#xff0c…