Go 里面的 ^ 和 &^
这几天在研究 Go 的源码,突然发现了一个之前没有见过的位运算,见这里
new &^= mutexWoken
& 和 ^,分别表示 AND 和 XOR,这个不用多说。
值得一提的是 ^ 这个符号,在我的印象中,它一直是一个二元运算符,平时见的最多的是 a ^ b 这种用法。
但是实际上它还是一个一元运算符。单走一个 a 也是没问题的,例如 ^a。
^ 作为一元运算符的作用
去知识的源头寻找答案!
在 Go 的规范文档的 Constant expressions 这一节中有提到 ^ 作为一元运算符的作用
The mask used by the unary bitwise complement operator
^matches the rule for non-constants: the mask is all 1s for unsigned constants and -1 for signed and untyped constants.^1 // untyped integer constant, equal to -2
uint8(^1) // illegal: same as uint8(-2), -2 cannot be represented as a uint8
^uint8(1) // typed uint8 constant, same as 0xFF ^ uint8(1) = uint8(0xFE)
int8(^1) // same as int8(-2)
^int8(1) // same as -1 ^ int8(1) = -2
^a: 当 a 是 unsigned 时,相当于用 11111... (... 表示很多很多 1) 与 a 做异或运算;当 a 是 signed 时,相当于用 -1与 a 做异或运算
PS: 无论 int 还是 uint ,其底层都是用 bit 表示的,而 -1 用补码表示就是 1111... ,如果从 bit 的角度出现,可以发现,无论 a 是正数还是负数最终都是与 1111... 做 XOR 运算!而最终的效果则是将 a 所有的 bit 位的值全部反转
让我们来推导一下,首先复习一下反码和补码的知识:
反码: 正数的反码等于本身,负数的反码保持符号位不变,其他位取反
补码: 正数的补码等于它本身,负数的补码等于它的反码加一
下面为了表示方便,正数和负数用到 8 位 bit 表示,即 int8 和 uint8 。
| 类型 | 值 | 原码 | 反码 | 补码 |
|---|---|---|---|---|
| int8 | 1 | 0000 0001 | 0000 0001 | 0000 0001 |
| int8 | -1 | 1000 0001 | 1111 1110 | 1111 |
| uint8 | 1 | 0000 0001 | 0000 0001 | 0000 0001 |
| int8 | -2 | 1000 0010 | 1101 | 1111 1110 |
| uint8 | 254 (255 - 1) | 1111 1110 | 1111 1110 | 1111 1110 |
^1 // untyped integer constant,使用 -1 与其做 XOR 运算 1111 1111 ^ 0000 0001 = 1111 1110, 恰好为 -2 的补码
uint8(^1) // illegal: same as uint8(-2), -2 cannot be represented as a uint8
^uint8(1) // typed uint8 constant, same as 0xFF ^ uint8(1) = uint8(0xFE)
int8(^1) // same as int8(-2)
^int8(1) // same as -1 ^ int8(1) = -2
&^ 的作用
回到 &^ 上面来,在 Arithmetic_operators 这一节中记录了 &^ 这个运算符。
&^ bit clear (AND NOT) integers
实际上 a &^ b 的效果近似于 a & (^b),即将 ^b 的结果与 a 做 AND 运算。
&^ 名为 bit clear,他的作用自然也就是 bit clear,a &^ mask 会将 a 中一些位置的 bit 值 clear 为 0,通过将 mask 中 bit 值设置为 1 来指定位置。
例如
pos 12345
a = 11001
mask = 01010
mask 的第 2 和第 4 位的 bit 为 1,则意味着将 a 的第 2 位和第 4 位的 bit clear 为 0,因此 a &^ mask 的结果为 10001。
证明过程也很简单,之前说过 ^mask 的结果是将 mask 的 bit 位全部取反,所以 mask 内原本为 1 的 bit 就变成了 0,之后再与 a 做 AND 运算,任何 bit 值与 0 做 AND 运算的结果都为 0。
a &^ b 与 a & ^b
上面提到过 a &^ b 的效果近似于 a & (^b),但是它两还是有一点微笑区别的。具体可见 stackoverflow 的这个问题: Why does Go have a "bit clear (AND NOT)" operator?
There's a subtle difference that makes dealing with literals and untyped constants easier with the explicit bit clear operator.
Untyped integers have their default type as int so something like
a := uint32(1) & ^1is illegal as ^1 is evaluated first and it's evaluated as ^int(1), which equals -2.a := uint32(1) &^ 1is legal however as here 1 is evaluated as uint32, based on the context.There could also be some performance gains in having an explicit bit clear, but I'm not too sure about that.
感触
哭,用了快两年的 Go,居然连 Go 的语法都还没学完!
随机推荐
- (第二章第二部分)TensorFlow框架之读取图片数据
系列博客链接: (第二章第一部分)TensorFlow框架之文件读取流程:https://www.cnblogs.com/kongweisi/p/11050302.html 本文概述: 目标 说明图片 ...
- SpringSecurity原理解析以及CSRF跨站请求伪造攻击
SpringSecurity SpringSecurity是一个基于Spring开发的非常强大的权限验证框架,其核心功能包括: 认证 (用户登录) 授权 (此用户能够做哪些事情) 攻击防护 (防止伪造 ...
- appium滚动查找屏幕外的控件
嗯,还是把自己做的实验保存一下 Appium1.12.1+python2.7 实验滚动,查找屏幕外控件以及控制seekbar scroll() 是根据页面中两个元素位置之间的距离进行滑动. 滑动寻找屏 ...
- laravel 怎么获取public路径
app_path() app_path函数返回app目录的绝对路径: $path = app_path(); 你还可以使用app_path函数为相对于app目录的给定文件生成绝对路径: $pa ...
- Netty异步Future源码解读
本文地址: https://juejin.im/post/5df771ee6fb9a0161d743069 说在前面 本文的 Netty源码使用的是 4.1.31.Final 版本,不同版本会有一些差 ...
- 前端好用API之Fullscreen
前情 在前端开发需求中,特别网页有视频需求时,需要做视频全屏功能,或者在某些可视化大屏项目也要做全屏. Fullscreen介绍 让你可以简单地控制浏览器,使得一个元素与其子元素,如果存在的话,可以占 ...
- Struts2搭建及利用OGNL表达式弹出计算器
0x01 环境搭建 1.创建Struts2应用 创建一个动态网站项目 2.配置Tomcat启动环境 3.在WebContent目录下的WEB-INF文件夹中创建web.xml,Tomcat启动时会加载 ...
- 《前端运维》三、Docker--1镜像与容器
一.基本概念 如果我们想要让软件运行起来,首先要保证操作系统的设置,其次还需要依赖各种组件和库的正确安装.那么虚拟机就是一种带环境安装的一种解决方案,它可以实现在一种操作系统里面运行另外一种操作系统, ...
- bzoj4044/luoguP4762 [Cerc2014]Virus synthesis(回文自动机+dp)
bzoj4044/luoguP4762 [Cerc2014]Virus synthesis(回文自动机+dp) bzoj Luogu 你要用ATGC四个字母用两种操作拼出给定的串: 1.将其中一个字符 ...
- 使用postman进行post请求传递中文导致后台接收乱码的问题
1.个人猜测估计是如果header里不指明编码的话,经过tomcat服务器时会导致转换乱码信息,这样就算你在filter里配置了EncodingFilter相关的过滤器也无济于事.. 解决方法就是在h ...