取反运算符 和 位移运算符

我其实是有疑惑在里面, 下面会提到。

 

首先来段代码:

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.

 

如果有错误请指正, 也可以吐槽。

posted @ 2014-02-15 06:23  censai  阅读(1478)  评论(0编辑  收藏  举报