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

深入解析C语言位运算与操作符

目录

1. 原码,反码,补码

2. 移位操作符

2.1 左移操作符

2.2 右移操作符

3. 位操作符:&,|,^,~

3.1 按位与:&

3.2 按位或:|

3.3 按位异或:^

3.4 按位取反:~

3.5 一道比较变态的面试题

3.6 练习

练习1

练习2

4. 逗号表达式

5. 下标访问[],函数调用()

5.1 [] 下标引用操作符

5.2 函数调用操作符()

1. 原码,反码,补码

原码:直接将数值按照正负数的形式编译成二进制得到的就是原码。

反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。

补码:反码+1就得到补码。

补码得到原码也是可以使用:取反,+1的操作。

正整数的原,反,补码都相同。

负整数的三种表示方法各不相同。

举个例子:

于是,我们便可以总结出它们之间的关系:

我们可以发现,直接从补码得到原码是采用先取反,再+1的操作,那么是这样的吗,我们可以举个例子:

那么可能会问,研究原码,补码有什么用呢?
其实,整数在内存中存储的时候使用的是补码,

CPU在计算的时候也是使用补码计算的,

但是打印出来,或者人使用的时候都是原码。

2. 移位操作符

<<左移操作符

>>右移操作符

注:移位操作符的操作数只能是整数。

2.1 左移操作符

移位规则:左边抛弃,右边补0。

举个例子:

从上面的例子中,我们可以发现:10左移1位,变成了20,

可这是为什么呢?

其实,我们可以根据左移位规则来推断:

像这样移位之后,再从右往左依照二进制的计算方法便可以得到20。

1.将num移动1位后的结果赋值给了r;

2.实际上num的值是不变的。

注意:进行移位操作时,是对补码进行移位,而最后打印是将补码转化为原码,再对原码进行打印。

2.2 右移操作符

移位规则:首先右移运算分两种:

1.逻辑右移:左边用0填充,右边丢弃;

2.算术右移:左边用原该值的符号位填充,右边丢弃。

说明:逻辑右移与上述左移相似,

算术右移:如果是正数,通通补0;

如果是负数,通通补1。

警告:对于移位运算符,不要移动负数位,这个是标准未定义的。

例如:

3. 位操作符:&,|,^,~

注意:它们的操作数必须是整数(字符类型)。

3.1 按位与:&

a&b:(拿a与b的补码进行计算,对应二进制位上有0则为0,2个同时为1才为1,算出的结果为补码)

举个例子:

3.2 按位或:|

它与按位与做法相似,只不过在计算时,只要有1则为1,两个同时为0才为0

举个例子:

3.3 按位异或:^

运算规则:相同为0,相异为1。

举个例子:

3.4 按位取反:~

运算规则:原本是1全变为0,原本是0,全变为1。

举个例子:

3.5 一道比较变态的面试题

问题:

不能创建临时变量(第三个变量),实现两个整数的交换。

可以看出,以上这种方法,确实符合题意,不存在第三个变量,也实现了两个数的交换,但这种方式也存在一定的风险:如果a和b非常大,a+b的值超出整型表示的最大值,则可能会出现溢出的问题。

那么我们应该如何解决呢?

这时,我们可以试试异或:

使用异或后,我们可以发现,a与b发生了交换,那其中的原理又是什么呢?

首先我们要知道异或的运算规则是:相同为0,相异为1。

且a^0=a,a^a=0,

于是我们可以知道:3^5^3=5,3^3^5=5。

所以,异或是支持交换律的。

有了上面的发现,我们再来看下上面那道问题。

所以便可以得以解决。

3.6 练习

练习1

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

其实,内存中的二进制中1的个数就是指补码的二进制中1的个数。

这时候我们可以联想一下,之前我们是如何求十进制中的每一位的呢?

就是进行%10,/10的操作,那对于二进制,类比可知,也就是对其进行%2,/2的操作,于是便可以这样编写代码:

可是这个代码就是完全正确的吗?

可以发现,当我们输入-1的时候,输出补码中1的个数为0,很显然这是错误的。

那我们应该怎么做呢?
我们这时候可以试着借助按位与(&),

-1&1: 10000000 00000000 00000000 00000001 -----(-1的原码) 11111111 11111111 11111111 11111110 -----(-1的反码) 11111111 11111111 11111111 11111111 -----(-1的补码) 00000000 00000000 00000000 00000001 -----( 1的补码)

当我们将-1&1时,便可以得到-1中的二进制中最低位的值,将-1换位任意数也是一样,

当num&1==1时,就说明num的最低位是1;

当num&1==0时,就说明num的最低位是0。

那如果要检验num的其他位是否也为1该怎么做呢?

这时,就可以使用我们学过的右移位操作符,使其右移1位。

因此:

所以,使用这种方法,计算出来的值便是正确的!

但其实这也不是最终方法,还有一种方法:

首先,做个铺垫,先给出一个表达式:

n=n&(n-1)

假设n=13,其二进制位1101,于是:

n= 1101 n=1= 1100 新的n= 1100 n-1= 1011 n= 1000 n-1= 0111 n= 0000 ​

于是我们可以发现,每当n&(n-1)时,n的二进制从右往左数遇到的第一个1会被去掉,就像上面的例子一样,去1这个操作被执行了三次,说明其中有3个1。

因此:

int main() { int num = 0; int count = 0; scanf("%d", &num); int i = 0; while (num) { num = num & (num - 1); count++; } printf("%d\n", count); return 0; }

这种方法就比上面的方法更加高效,因为上面那种方法无论有几个1,都会执行32次,而这种方法有几个1,就执行几次,相比之下就更加高效了。

练习2

问题:二进制位置0或者置1

编写代码将13二进制序列的第5位修改为1,然后再改回0

结合以上知识,便可以得出:

4. 逗号表达式

逗号表达式:从左向右依次计算,整个表达式的结果时是最后一个表达式的结果

举个例子:

注意:一定要先从左向右依次计算,最后再取最后一个表达式的结果。

5. 下标访问[],函数调用()

5.1 [] 下标引用操作符

5.2 函数调用操作符()

http://www.jsqmd.com/news/604084/

相关文章:

  • 【实测】GitNexus实测:拖入GitHub链接秒出代码知识图谱,今天涨了857星
  • 告别论文 AI 痕迹 + 重复率双杀!Paperxie 四大功能硬核拆解,本科生闭眼冲
  • 告别龟速下载!用国内镜像5分钟搞定QT6在线安装(附命令行参数详解)
  • MCGS 基于PLC的风力发电控制系统 带解释的梯形图程序,接线图原理图图纸,io分配
  • 从零基础到上手:Trae AI编程编辑器新手入门实时预览网页文件
  • DDD 架构重构实践:AI Skills 如何赋能DDD设计与重构
  • 雀魂AI助手Akagi:革新麻将竞技的智能决策系统
  • RAG 不需要向量库?无向量检索新范式全攻略(非常硬核),大模型检索从入门到精通,收藏这一篇就够了!
  • OpenClaw+千问3.5-9B:个人日程智能管理系统
  • 效率提升:让快马ai为你生成鸿蒙pc版文件管理器的核心界面代码
  • 别再写runtime循环了!用constexpr生成LUT表的7步安全范式(含SPI驱动、FFT预计算、游戏状态机全场景代码模板)
  • 西门子S7_200PLC与MCGS组态在污水处理控制设计中的应用
  • 破局双检!Paperxie 四大核心:毕业论文降重 + 降 AIGC 双效突围,改写学术合规新生态
  • 嵌入式通信基础:同步、异步?全双工、半双工??
  • 新手福音:用快马生成带详解注释的Android Studio首个应用
  • 2026年热门ai视频总结工具实测对比,差距竟然这么大,低调真香黑马才是真王者
  • PC电脑版 微信WeChat 多开防撤回最新版 带提示绿色版 安装版
  • IDEA中Module工程重命名的正确姿势与避坑指南
  • JavaScript中函数体代码量对V8内联优化特性的影响
  • Vaptcha手势验证码实战:3分钟搞定Discuz论坛安全升级(附避坑指南)
  • 清明节给婆婆爷爷外公外婆上坟挂清 ☜请点击这里可看全文
  • 分布式锁:从入门到入土,看这一篇就够了!
  • 从零到精通:MySQL多平台安装全攻略
  • 利用快马AI快速原型开发:十分钟打造你的首个谷歌浏览器笔记扩展
  • 2026届必备的AI学术方案横评
  • Python flask django旅游攻略 克州旅游网站的景区酒店门票预订系统
  • d2s-editor:重构暗黑破坏神2存档体验的4大创新实践
  • 2026最权威的十大AI科研平台实际效果
  • GAS进阶:如何扩展虚幻引擎技能系统实现自定义游戏机制(基于GASDocumentation深度解析)
  • ThinkBook 16 2024款装Ubuntu 22.04,无线网卡和蓝牙驱动修复保姆级教程