移位运算:
- 逻辑移位
逻辑移位是指逻辑左移和逻辑右移,移出的空位都用0来补。
- 算术移位
算术移位 就需要分有符号型值和无符号型值 :
- 对于无符号型值,算术移位等同于逻辑移位。
- 而对于有符号型值 ,算术左移等同于逻辑左移,算术右移补的是符号位,正数补0,负数补1。
其中,第2点涉及到负数在计算机中的存储方式:
首先复习一下原码、反码、补码:
有符号型值分为正数和负数(包括正浮点数,和负浮点数),规定最高位为符号位,正数为0,负数为1。
原码:10进制转换成2进制是原码,只不过正数的原码是本身符号位为0,负数的原码符号位为1(1的原码是0000 0001,-1的原码是1000 0001)。
反码: 正数的反码是本身,负数的反码是负数的原码非符号位0变为1,1变为0(-1的原码是1000 0001 它的反码就是 1111 1110)。
补码: 正数的补码是本身,负数的补码就是负数的反码加1(-1的原码是1000 0001,它的反码就是 1111 1110 它的补码就是 1111 1111)。
总结:正数的原码,反码 ,补码三值合一, 负数的原码,反码,补码不同。事实证明,计算机中负数是以补码存储的,也可以推广到——计算机中所有数都是以补码形式存储的。
!!!补码求原码的过程,依然是(1)符号位不变,其它位取反;(2)符号位不参与计算,其余加1。
详见原文:负数在计算机中的存储问题
因此,负数的算术右移,实际上是对补码的右移。比如:
char i=-8;//原码为1000 1000,反码为1111 0111,补码为1111 1110;
i>>=3; //右移3位,即补码右移3位,变成:
//补码为1111 1111,取反为10000 0000,加1为1000 0001,为-1;
VS系列的编译器中,对无符号型值进行移位时,默认是逻辑左移和逻辑右移;
而对于有符号型值进行移位时,左移还是逻辑左移,但右移时执行的是算术右移。