当前位置: 首页 > news >正文

C:关于位操作符:、|、^、~的一些应用

一些用来熟悉位操作符的应用

一、按位异或:^

异或运算:相同为0,相异为1

应用:在不引入临时变量(第三变量)的情况下,实现两个整数的交换。

关于两个整数交换,我们有一些方法,比如说,创建一个第三变量,就可以很轻易的实现两个整数的交换,如下代码:

#include <stdio.h>
int main()
{int a = 10;int b = 20;printf("交换前:a=%d b=%d\n", a, b);int c = a;a = b;b = c;printf("交换后:a=%d b=%d\n", a, b);return 0;
}

但是,该程序引用了第三个变量,如果不引入第三个变量,我们又有什么办法来实现两个整数的交换呢?

这里我们就可以使用按位异或操作符^来达到想要的目的。

代码展示:

#include <stdio.h>
int main()
{int a = 10;int b = 20;printf("交换前:a=%d b=%d\n", a, b);a = a ^ b;b = a ^ b;a = a ^ b;printf("交换后:a=%d b=%d\n", a, b);return 0;
}

相信你看到这个程序可能会有一点懵并充满疑惑,这是怎么实现的?

在解析这串代码之前,我们需要了解一些知识来为读懂代码做准备。

异或运算:相同为0,相异为1

int a =3;

int b = 5;

a的二进制表示:011

b的二进制表示:101

1. a^a = 0

a = 011

a = 011

a^a = 000

我们可以知道,整数和它自己本身异或得到的结果是0

2. a^0 = a

a = 011

0 = 000

a^0 = 011

我们可以得到,整数和0异或得到的结果是整数本身

当我们知道这些信息后,我们就可以解析这串代码了

a = a ^ b;
b = a ^ b;
a = a ^ b;

 开始时,将a ^ b的值赋给a,因此,b = a ^ b表达式中的a的值就变为a ^ b,通过异或运算,我们可以得到b=a,这时候,b的值就变为a了,但是a的值没有变化,还是 a ^ b,因此,在a = a ^ b表达式中, a ^ b中a的值还是a ^ b,b的值变为了a,通过异或运算,我们可以得到 a=b。

下面是图解:

图片或许表达的不是很清楚,如果有不明白的,可以私我,欢迎!

二、按位与:&

与运算:有0为0,全1为1

应用:求一个整数存储在内存中的二进制中1的个数

法一:通过判断整数的最后一位

int n = 15;  
int count = 0;//二进制中1的个数

将15与1进行 与运算 15&1

00000000000000000000000000001111   //15的二进制表示
00000000000000000000000000000001  // 1的二进制表示
00000000000000000000000000000001  //与运算结果
通过与运算结果是1,我们可以判断出15的最低位是1

因此,如果想得到n的二进制最低位,我们就可以给n按位与上一个1,通过判断结果是0还是1来确定n的二进制最低位是什么。

当我们得到最后一位后,如果结果是1的话,我们就count++,该最低位统计过后,我们需要统计倒数第二位,该怎么办呢?

我们可以通过右移操作符 >> 向右移动一位,这样就可以丢掉已经统计过的最低位,这样倒数第二位就来到了最低位,然后再按位与1,判断结果,如果结果是1,就count++,如果结果是0,则count的值不变,重复操作32次后,我们就可以判断完每一位是否为1,从而得到整数存储在内存中的二进制中1的个数。

for (int i = 0; i < 32; i++)//一个整型是4个字节,一个字节8个bit,这里的32就是32个bit位{if (((n >> i) & 1) == 1)count++;}

这段代码使用一个循环来检查整数 n 的二进制表示中值为 1 的位的数量。 具体来说,循环从 0 迭代到 31 。对于每次迭代 i ,首先将 n 向右移动 i 位,然后与 1 进行按位与操作。如果结果为 1 ,说明 n 右移 i 位后的最低位是 1 ,此时就将计数器 count 的值增加 1 。当循环结束时,count 中存储的就是 n 的二进制表示中 1 的个数。

完整代码:

#include <stdio.h>
int main()
{int n = 0;scanf("%d",&n);int count = 0;//二进制中1的个数for (int i = 0; i < 32; i++)//一个整型是4个字节,一个字节8个bit,这里的32就是32个bit位{if (((n >> i) & 1) == 1)count++;}printf("%d\n", count);return 0;
}

从上面代码,我们可以发现一些问题,就是不管所求数的二进制中有几个1,都需要循环32次

我们可以修改一下

法二:

int n = 13

表达式n = n & (n-1)

13的二进制序列:1101

n = n-1
第一组n和n-1
1101 --n
1100 --n-1
1100 --新的n
将新的n与原来相比,可以看到少了一个1,且是最后一位
第二组n和n-1
1100 --新的n
1011 --n-1
1000 --新的n
与第二个n相比,可以看到最右边的1又没了
第三组n和n-1
1000 --新的n
0111 --n-1
0000 --新的n
与上一个n对比,1又消去了。

从上面的例子,我们应该也能看出表达式n = n & (n-1)的作用:让n的二进制序列中最右边的1消失

n = n & (n-1)表达式每执行一次,就会去掉一个1,知道n中的1全部被去掉为止,因此,我们可以通过表达式进行的次数,来计算n二进制序列中有几个1

代码展示:

#include <stdio.h>
int main()
{int n = 0;scanf("%d",&n);int count = 0;//二进制中1的个数while(n){n = n & (n-1);count++;}  printf("%d\n", count);return 0;
}

该程序的好处是不会产生额外的循环,n的二进制序列中有几个1,就循环几次,没有就不循环。

 

三、按位或:| 按位取反:~

或运算:有1为1,全0为0

应用:将13的二进制序列的第5位修改位1,然后再改回0

13的二进制序列:00000000000000000000000000001101
将第5位置改为1:00000000000000000000000000011101
再将第5位改回0 :00000000000000000000000000001101

00000000000000000000000000001101
00000000000000000000000000010000
或结果:
00000000000000000000000000011101

那么00000000000000000000000000010000该怎么得到呢?

我们可以将1的二进制序列通过左移操作符向左移动4位 (1<<4)

这样就可以得到想要的结果了

代码展示:

#include <stdio.h>
int main()
{int n = 13;n |= (1 << (5-1));//将第5位0改为1printf("%d\n", n);	return 0;
}

那么我们该怎么改回去呢?

这里我们就要用到&和~了

因此,代码展示:

#include <stdio.h>
int main()
{int n = 13;n |= (1 << (5-1));//将第5位0改为1printf("%d\n", n);	//29n &= (~(1 << (5 - 1)));//将第5位改回来printf("%d\n", n);//13return 0;
}


本篇文章到这里就结束了,期待你们的下次到来!!!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 百日筑基第三十七天-阿里开发手册编程规约
  • 编程实践|如何用 MoonBit 实现 diff(三)
  • 使用css在照片右上角设置缎带效果
  • 请以零基础学Python 之 第二十讲 分组和贪婪匹配
  • 从新手到高手:Scala函数式编程完全指南,Scala 文件 I/O(27)
  • 【LLM】-10-部署llama-3-chinese-8b-instruct-v3 大模型
  • 类似redmine的项目管理系统有哪些?10款软件测评
  • 基础跟张宇,强化换武忠祥可行吗?会不会漏什么?
  • Flask目录结构路由重定向简单实例讲解——轻量级的 Python Web 框架
  • 【数据结构】——堆的实现与算法
  • ElasticSearch父子索引实战
  • 怎么用U盘重装系统
  • ansible笔记
  • go 语言踏出第一步
  • 【Stable Diffusion】(基础篇七)—— lora
  • [译]Python中的类属性与实例属性的区别
  • Date型的使用
  • input实现文字超出省略号功能
  • Java 23种设计模式 之单例模式 7种实现方式
  • java正则表式的使用
  • JS函数式编程 数组部分风格 ES6版
  • ng6--错误信息小结(持续更新)
  • passportjs 源码分析
  • php的插入排序,通过双层for循环
  • Python 基础起步 (十) 什么叫函数?
  • React的组件模式
  • SQL 难点解决:记录的引用
  • Vue.js源码(2):初探List Rendering
  • 从tcpdump抓包看TCP/IP协议
  • 从伪并行的 Python 多线程说起
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 记一次和乔布斯合作最难忘的经历
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 漂亮刷新控件-iOS
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 小程序01:wepy框架整合iview webapp UI
  • 移动端唤起键盘时取消position:fixed定位
  • 运行时添加log4j2的appender
  • 终端用户监控:真实用户监控还是模拟监控?
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • # Maven错误Error executing Maven
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • #C++ 智能指针 std::unique_ptr 、std::shared_ptr 和 std::weak_ptr
  • #ubuntu# #git# repository git config --global --add safe.directory
  • $(this) 和 this 关键字在 jQuery 中有何不同?
  • (2024,Flag-DiT,文本引导的多模态生成,SR,统一的标记化,RoPE、RMSNorm 和流匹配)Lumina-T2X
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (六)Flink 窗口计算
  • (亲测有效)解决windows11无法使用1500000波特率的问题
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • ****三次握手和四次挥手