位运算基本知识浅谈
简介
我们知道,计算机中所有数都是二进制存储的
位运算就是对正数的二进制位进行的运算
运算说明
首先明确一点,位运算是对正数进行的运算,所以下面的各语句中,变量类型均默认定义为int
按位取反not
表达式~a
,按二进制位运算,将每一位取反
简单来说,即“0变1,1变0”
左移shl
表达式a << n
,其中n
为正整数,表示在二进制下,将a
左移n
位(在a
的二进制表示后面添上n
个0)
实际上等于$a*2^n$
右移shr
表达式a >> n
,其中n
为正整数,表示在二进制下,将a
右移n
位(将a
的二进制表示后面n
位舍弃)
实际上等于$\lfloor{\frac{a}{2^n}}\rfloor$
按位与and
表达式a & b
,按二进制位运算,位数较小的补齐前导0,对于每一位,二进制表示均为1,则结果为1,否则为0
简单来说,即“有0得0,全1得1”
按位或or
表达式a | b
,按二进制位运算,位数较小的补齐前导0,对于每一位,二进制表示均为0,则结果为0,否则为1
简单来说,即“有1得1,全0得0”
按位异或xor
表达式a ^ b
,按二进制位运算,位数较小的补齐前导0,对于每一位,二进制表示两变量相异为1,相同为0
简单来说,即“相同得0,相异得1”
异或的逆运算
异或的逆运算是它本身,也就是说,一个值两次异或同一个值,最后得到它本身,即a == a ^ b ^ b
异或的简单运用
由“异或的逆运算是它本身”
,我们可以发散思维,得出异或的一些简单运用
简单加密
如果你得到一个整数作为明文,想要加密,最简单的方法就是选取另一个整数作为密钥,对明文和密钥进行异或运算,结果即为得到的暗文,而接收暗文的人只需手持一样的密钥,将暗文与密钥进行异或运算,即可重新得到明文
(似乎没有什么用的) 不需要中间变量的交换过程
现在,有两个变量,a
与b
,需要将两个变量的值交换,又不想定义中间变量,那可以考虑用异或运算进行交换,代码是这样的:1
2
3a ^= b;
b = a ^ b;
a ^= b;
现在来考虑这段代码执行交换的合理性,之前提到过,a == a ^ b ^ b
,那么第一行中a ^= b
后a
的值变为a ^ b
,再到第二行执行时,相当于b
的值被重新赋值为a ^ b ^ b
,也就是a
变量的初值,最后到第三行执行时,a
的值则被赋值为a ^ b ^ a
,也就成了b
变量的初值,完整实现了交换功能
小拓展:
上述交换功能的本质是对于互逆运算的如下利用:
定义符号$与#,使之互为逆运算
对于如下代码块1
2
3a <- a # b
b <- a $ b
a <- a $ b
执行第一句后a
的值变为a # b
,第二句执行时b
的值被赋为a # b $ b
,由于$与#互逆,则a # b $ b = a
,所以b
的值被赋为a
变量的初值,同理,第三行使a
被赋值为b
变量的初值
正因为异或运算的逆运算是其本身,才会有看起来这样离谱的交换代码
同样是这个本质,加减互为逆运算,用起来就不会像异或这样看起来十分离谱1
2
3a += b;
b = a - b;
a -= b;
运算优先级
所有运算后赋值操作<或<异或<与<左移=右移<其他所有除括号以外的运算<取反<括号
括号yyds
总结
本文简单陈述了C语言基础知识位运算,并对异或运算进行了小小的拓展,尽可能浅显地使阅读本文的诸君理解位运算,望共勉之
P.S. 笔者如有陈述不周之处还望斧正