取反运算符 和 位移运算符
我其实是有疑惑在里面, 下面会提到。
首先来段代码:
void test2() { int i1 = ~0; int i2 = i1>>1; unsigned int u1 = ~0; unsigned int u2 = u1>>1; printf("int : %X -> %X, %d -> %d\n", i1, i2, i1, i2); printf("unsigned int: %X -> %X, %u -> %u\n", u1, u2, u1, u2); } /*** Print *****/ int : FFFFFFFF -> FFFFFFFF, -1 -> -1 unsigned int : FFFFFFFF -> 7FFFFFFF, 4294967295 -> 2147483647 /****/
取反运算符(~):
计算变量的反码。
位移运算符(<< 或 >>):
将一个数的各二进制位左或右移若干位。
左移运算符(<<): 各二进制位左移若干位,移动的位数由右操作数指定,操作数不为负数, 右边空出的位用0填补,高位左移溢出则舍弃该高位。
右移运算符(>>): 各二进制位右移若干位,移动的位数由右操作数指定,操作数不为负数, 移到右端的低位被舍弃,高位填补有以下情况:
对于无符号数,高位补0。即右移时左边高位移入0;
对于有符号数,某些机器将对左边空出的部分用符号位填补(“算术移位”),而另一些机器则对左边空出的部分用0填补(“逻辑移位”)。
如果原来符号位为0(该数为正),则左边也是移入0。
如果原来符号位为1(该数为负),则左边移入0还是1,要取决于所用的计算机系统。有的系统移入0,有的系统移入1。移入0的称为“逻辑移位”,即简单移位;移入1的称为“算术移位”。
Note: 计算机中0的原码有+0和-0, 我实在CentOS测试的, 这里的0原码是-0(至于为什么不是+0, 我这真不知道, 这就是我想提问的问题,也求解答)。系统右移操作为“算数位移”。
我解析以下上面的代码:
[-0]有符号型 = [1000 0000 0000 0000 0000 0000 0000 0000]原
= [1111 1111 1111 1111 1111 1111 1111 1111]反
= [0000 0000 0000 0000 0000 0000 0000 0000]补
[-1]有符号型 = [1000 0000 0000 0000 0000 0000 0000 0001]原
= [1111 1111 1111 1111 1111 1111 1111 1110]反
= [1111 1111 1111 1111 1111 1111 1111 1111]补
[4294967295]无符号型 = [1111 1111 1111 1111 1111 1111 1111 1111]原、反、补码
[2147483647]无符号型 = [0111 1111 1111 1111 1111 1111 1111 1111]原、反、补码
void test2() { int i1 = ~0; //取得0的反码。 这时 i1 的二进制数为 [1111 1111 1111 1111 1111 1111 1111 1111] = [-1]补码 , 这里是有符号的 int i2 = i1>>1; //有符号变量右移操作,这里是算数位移。这时 i2 的二进制数为 [1111 1111 1111 1111 1111 1111 1111 1111] = [-1]补码 , 这里是有符号的 unsigned int u1 = ~0; //取得0的反码。这时u1 的二进制数为 [1111 1111 1111 1111 1111 1111 1111 1111] = [4294967295]原码, 这里是无符号的 unsigned int u2 = u1>>1; //无符号变量右移操作,高位直接上0, 这时u2 二进制数为 [0111 1111 1111 1111 1111 1111 1111 1111] = [2147483647]原码, 这里是无符号的,高位直接上0 printf("int : %X -> %X, %d -> %d\n", i1, i2, i1, i2); //输出十六进制,十进制, 计算机以补码形式存储负数, 所以i1 = i2 = -1; printf("unsigned int: %X -> %X, %u -> %u\n", u1, u2, u1, u2); //输出十六进制,十进制, }
可能说的不太清晰, 自己认真去想想还是能懂的。
我的关键问题在于为什么这里0不是+0.
如果有错误请指正, 也可以吐槽。