代码改变世界

c 位运算

2017-07-18 14:59  ZengGW  阅读(656)  评论(0编辑  收藏  举报

声明:位运算根据不同的操作系统得出的结果可能不同,在此我是根据 8位机 来做的介绍

优先级:! > 算术运算符 > 关系运算符 > && > || > 赋值运算符

一、位运算:

  位运算的运算分量只能是整型或字符型数据,位运算把运算对象看作是由二进位组成的位串信息,按位完成指定的运算,得到位串信息的结果。

  常用的位运算有 AND(&)、OR(|)、NOT(~)、EXCLUSIVE-OR(异或^)、同一运算(I 大写的i)、移运算(左移运算 << 、右移运算 >>)

  位运算符的优先级从高到低,依次为~、&、^、|, 其中~的结合方向自右至左,且优先级高于算术运算符,其余运算符的结合方向都是自左至右,且优先级低于关系运算符。

二、介绍运算(转换成2进制位进行运算

1. AND(&) 按位与运算(将两个运算分量的对应位按照一定的规则就行运算):

  规则:相同位置的位的值都是1,则结果为1,否则即为0

  比如:1 & 0 、3 & 2 、4 & 2 、6 & 2

  转换2进制:00000001  & 00000000(1 & 0)、00000011 & 00000010(3 & 2)、00000100 & 00000010(4 & 2)、00000110 & 00000010(6 & 2

  换种形式:00000001、00000011、00000100、00000110 

       00000000、00000010、00000010、00000010

  结果:1 & 0 = 0、3 & 2 = 2、4 & 2 = 0、6 & 2 = 2

  按位与运算就是集合的交集,很简单,A = {0,2,3,6}, B = {0,1,4,6},那么A与B的交集就是{0,6}

2. OR(|)按位或运算(将两个运算分量的对应位按照一定的规则就行运算):

  规则:相同位置的位的值只要有1个值是1,结果就是1,否则即为0

  比如:1 | 0 、2 | 1 、6 | 2 、8 | 3

  转换2进制:00000001 | 00000000(1 | 0)、00000010 | 00000001(2 | 1)、00000110 | 00000010(6 | 2 )、00001000 | 00000011(8 | 3

  换种形式:00000001 00000010 00000110 00001000 

         00000000 00000001 00000010 00000011

  结果:1 | 0 = 1、2 | 1 = 3、6 | 2 =  6、8 |  3 = 11

  按位或运算就是集合的并集,根据规则就可以看得出了,比如10000001 | 011111110,那结果就是这两个二进制数的合并,也就是11111111

3. EXCLUSIVE-OR(异或^)按位异或运算(将两个运算分量的对应位按照一定的规则就行运算):

  规则:相同位置的位的值相同的,结果为0,不相同的结果为1

  比如:1 ^ 2、0 ^ 0、3 ^ 6、9 ^ 1

  转换2进制:00000001 ^ 00000010(1 ^ 2)、00000000 ^ 00000000(0 ^ 0)、00000011 ^ 00000110(3 ^ 6)、00001001 ^ 00000001(9 ^ 1

  换种形式:00000001 、00000000 、00000011 、00001001 

       00000010 、00000000 、00000110 、00000001

  结果:1 ^ 2 = 3、0 ^ 0 = 0、3 ^ 6 = 5、9 ^ 1 = 8

 4. NOT(~)按位取反运算(按位取反运算是单目运算,用来求一个位串信息按位的反)

  规则:二进制位的值,为1的结果是0,为0的结果是1

   比如: ~7 、~9、~0、~10

  转换2进制:00000111(7)、00001001(9)、000000(0)、00001010(10)

  转换结果:  11111000(~7)、11110110(~9)、11111111(~0)、11110101(~10)

  结果(16进制,10进制懒得算):~7 = 0xf8、~9 = 0xf6、~0 = 0xff、~10 = 0xf5

  按位取反运算就是“补运算”了,通过规则,比如:10001110 补运算的结果是:01110001,把二进制数和其补运算的结果合并在一起刚好是11111111

5. identity operation (I)同一运算:

  规则:

    (1). 如果两个值类型不相同,则它们不相等

    (2). NaN和其他任何值都是不相等的,包括它本身

    (3). 如果两个引用值指向同一个对象,数组或函数,则它们是相等的。如果指向不同的对象,则它们是不等的,尽管两个对象具有完全一样的属性

    如果不相同,则无法进行其他操作

  比如:a ^ I (a) = a ^ a = 0;

6. 移位运算(移位运算是双目运算,有两个运算分量,左分量为移位数据对象,右分量的值为移位位数。移位运算将左运算分量视作由二进位组成的位串信息,对其作向左或向右移位,得到新的位串信息,移位运算符的优先级低于算术运算符,高于关系运算符,它们的结合方向是自左至右。)

  1. 左移运算符(<<):

    规则:将一个位串信息向左移动指定的位置,右端空出的位补0,左端溢出的高位舍弃,且

    比如:-2  << 4 

    过程:-2 先转换成二进制(2进制的补码),00000010 -补码-> 11111101 + 1 -结果-> 11111110  -根据规则,往左移动4位,右端空出的位补0-> 111111100000 -根据系统位数8位机,左端溢出的高位要被舍去,结果保留8位-> 11100000 -转换成10进制是224,这是补码的结果,我们在逆运算转回去,这是负数,前面加上负号-> -00011111 - 结果是 -31,再减去1 -> -31-1 = -32

    结果:-2  << 4 = -32; (可能大家很疑惑2进制的补码怎么算,这里给个简单的公式,先把二进制取反,在加1,也就是先~按位取反操作再加上1,-2 = 00000010 = 11111101 + 1 = 11111110 = 254)

    比如:2 << 4

    过程:无符号整数就好算多了, 2 -二进制-> 00000010 - 根据规则往左移动4位,其实也就是在二进制的右端加4个0 -> 000000100000 - 根据系统位数8位机,高位要舍去,保留8位二进制数 -> 00100000- 转换成10进制 -> 32

  2. 右移位运算(>>):

    规则(分有符号数和无符号数):将一个位串信息向右移动指定的位置,右端溢出的位舍去

      1> 无符号右移:左端空出的位补0

      2> 有符号右移:

        移位前符号为0(正数):左端空出的位也补0; 

        移位前符号为1(负数):左端用0或者1补充,取决于计算机系统;负数右移补充0,称为“逻辑右移”;负数右移补充1,称为“算术右移”;

                     可以使用以下方法来测试自己系统针对负数右移的具体方法:printf("%d\n\n\n", -2 >> 4);

    无符号右移示例:

      比如:3 >> 3

      过程: 00000011 - 根据规则往右移动三位,左侧补充0 -> 00000000011 -右侧溢出舍去 -> 00000000 - 转换 -> 0

      结果: 3 >> 3 = 0;

    有符号右移:

      正数:跟上边无符号右移一样,不做演示

      负数:(上边说过负数如何转成2进制数表示,就是2进制的补码,先按位取反运算,再加1)

        比如:-2 >> 4

        过程:00000010 - 取反 -> 11111101 + 1 - 结果-> 11111110 ,计算到这里根据系统不同可能是“逻辑右移”,可能是“算术右移”

           逻辑右移:11111110 - 负数右移,左侧补充0为逻辑右移 -> 000011111110 - 根据系统位数8位,根据右移规则,右端溢出舍去,从左往右数8位,便是结果 -> 00001111 - 结果 -> 15

           逻辑右移结果:-2 >> 4 = 00001111(15) - 转换回2进制补码 -> -(11110000) -1 - 结果 -> -241

           算术右移:11111110 - 负数右移,左侧补充1为算术右移 -> 111111111110 - 根据系统位数8位,根据右移规则,右端溢出舍去,从左往右数8位,便是结果 -> 11111111 - 结果 -> 255

              算术右移结果:-2 >> 4 = 11111111(255) - 转换回2进制补码 -> 00000000 -1 - 结果 -> -1

 三、题目

  1.只使用位级和逻辑运算,编写一个C表达式,他等价于x==y。换句话说,当x和y相等时他将返回1,否则返回0

   答:因为 x ^ y 只会在x == y时为0,所以我们可以利用这一性质得到这个表达式其实就是 !(x ^ y)