C语言的左移和右移探索

下面的左移和右移的探索都以int和unsigned int类型为例,先说明一下32位int和unsigned int各自的取值范围,其中int为:-2147483648 ~ 2147483647,unsigned int为:0~4294967295。

int类型

   先说左移,左移就是把一个数的所有位都向左移动若干位,在C中使用的是<<运算符,等于将该数乘以若干个2。下面举几个个例子来说明左移一些要注意的情况:

例子1:左移导致符号位被覆盖

        int k = 0x40000000; //16进制的40000000,为2进制的0100 0000...0000
	printf("%d\n", k);
	k = k << 1;
	printf("%x\n", k);
	printf("%d\n", k);

结果为:


   k是正数,左移一位后为0x80000000(补码),对应的十进制为-214783648,很显然溢出了(实际上应该是1073741824*2=2147483648>2147483647,这超过了int类型的表示范围的最大值)。究其原因是左移时导致符号位0被1覆盖,成了1000 0000....0000(补码),十进制为-2147483648,是int所能表示的最小值。由此我们可以再进一步猜测,如果K再左移一位,那么1000 0000....0000变成了0000 0000....0000,那么就是0。(大家可以自己试试看 ^_^)。从上面来看,int类型左移时,符号位也要参与其中。

   另外如果左移到符号位的那位和符号位一致,那么左移就是成功的,本质上也就是没有超过其最大取值范围。例如:

        int k = 0x20000000; //16进制的20000000,为2进制的0010 0000...0000
	printf("%d\n", k);
	k = k << 1;
	printf("%x\n", k);
	printf("%d\n", k);
运行结果为:


可以看到左移结果是正确的。

再来看看负数情况如何:

        int k = 0xA0000000; //16进制的A0000000,为2进制的1010 0000...0000
	printf("%d\n", k);
	k = k << 1;
	printf("%x\n", k);
	printf("%d\n", k);
运行结果为:


   k是负数,左移一位后为0x40000000,对应的十进制为1073741824,很显然溢出了(实际上应该是-1610612736*2=-3221225472<-2147483648,这超过了int类型的最小表示范围)。究其原因是左移时导致符号位1被0覆盖,成了0100 0000....0000(补码),十进制为1073741824。因此,对于int类型左移时是要好好考虑是否超出了值的范围。

例子2、左移里的位数超过该数值类型的最大位数

        int k = 0x00000001; 
	printf("%d\n", k);
	k = k << 33;
	printf("%x\n", k);
	printf("%d\n", k);
在VS2013中,编译器会给出一个警告:


对于32位int,那么实际上k移动的是33%32后的余数,也就是1位。运行结果如下:



说完左移说右移,右移比左移相对简单:
右移的概念和左移相反,就是往右边挪动若干位,运算符是>>,相当于该数除以若干个2。
右移对符号位的处理和左移不同,对于有符号整数来说,右移会保持符号位不变,然后在左边填充0,例如:

        int k = 0x80000000; //16进制的80000000,为2进制的1000 0000...0000
	printf("%d\n", k);
	k = k >> 33;
	printf("%x\n", k);
	printf("%d\n", k);

运行结果:


   就是说,符号位向右移动后,正数的话补0,负数补1,也就是汇编语言中的算术右移。同样当移动的位数超过类型的长度时,会取余数,然后移动余数个位。关于正数右移大家可以试试0x40000000。

unsigned int类型

     对于无符号整数,没了符号位的覆盖问题,一切都简单许多。这里就简要总结一下:

     对于无符号整数的左移,如果超出范围(即最高位被挤掉),那么值是不正确的,也就是溢出,但绝对不会出现变成负数的情况。

     对于无符号整数的右移,由于没有了符号位,所以高位是直接补0。下面看两个例子即可:  

        unsigned int k = 0xfffffffe; 
	printf("%u\n", k);
	k = k << 1;
	printf("%x\n", k);
	printf("%u\n", k);
运行结果:


        unsigned int k = 0x0000010; 
	printf("%u\n", k);
	k = k >> 1;
	printf("%x\n", k);
	printf("%u\n", k);
运行结果:



你可能感兴趣的:(Thinking,in,C)