本文记录一下VC++6.0中C语言下的移位操作,主要考虑会不会溢出,以及符号位的处理。首先区别一下算术移位与逻辑移位:
*算术左移同逻辑左移
*算术右移高位补符号位
*逻辑右移高位补0
1、左移操作 <结论为:高位移出,低位补0>
1)无符号数
我们考虑一个特别的数:2147483647,恩,这个数很特别不用怀疑,2147483647是#include<limits.h>头文件中定义的INT_MAX,即整型有符号数的最大值。其二进制形式为:
01111111 11111111 11111111 11111111
令unsigned a = 2147483647, 左移两位后的结果为:11111111 11111111 11111111 11111100,可以通过执行以下代码验证,
int i; unsigned a = 2147483647; unsigned b; printf("%u\n",a<<2); printf("%u\n",a*4); b = a*4; for(i=1;i<=32;i++){//逆序输出b printf("%d",b&1); if(i%8==0) printf(" "); b = b>>1; }
2)正数,有符号数
我们令a = 2147483647,二进制:01111111 11111111 11111111 11111111,然后查看左移一位后的结果,即执行下面语句:
a = INT_MAX; printf("%d ",a<<1); printf("%d\n",a*2); //输出结果为-2 -2a由正数变成了负数,由此可见 发生了溢出。所以a此时的操作位去掉前面要移动的位数,不关心符号位,并在最右边补0,a在移位后的结果为:
11111111 11111111 11111111 111111110
有符号数在计算机中是以补码表示的,转换为原码为(第一位为符号位):
10000000 00000000 00000000 00000010
即为-2;
3)负数,有符号数
令a = -2147483647;即二进制编码(补码)为:
10000000 00000000 00000000 00000001
现在将a左移1位,得到的结果为2,由此可见移位操作为将高位移出,低位补0,移位后的结果为:
00000000 00000000 00000000 00000010
2、右移操作
1)无符号数 <逻辑右移,高位补0>
我们令a = 4294967295,这个也是个很特别的数,是#include<limits.h>中定义的UINT_MAX,即无符号数最大数,二进制为:
11111111 11111111 11111111 11111111
现在,我们将a右移一位,并查看结果,结果为2147483647,这个数是不是很熟悉?即INT_MAX,所以右移的操作为高位补0,结果为:
01111111 11111111 11111111 11111111
2)有符号数,正数 <算术右移,高位补符号位>
令a = INT_MAX,即01111111 11111111 11111111 11111111,右移一位后结果为:
00111111 11111111 11111111 11111111,显然,操作是高位补0
3)有符号数,负数 <算术右移,高位补符号位>
令a = -1,即:11111111 11111111 11111111 11111111,我们查看右移一位后的结果,执行下面命令:
int a = -1; printf("%d ",a>>1); int b = -2; printf("%d\n",b>>1); //输出 -1 -1我们可以看到-1,-2右移一位的结果都是-1,-1右移一位得-1好解释,-2也好解释,-2的二进制为
11111111 11111111 11111111 11111110
右移后得11111111 11111111 11111111 11111111,即-1。
3、总结
VC++6.0可以认为都进行的是算术移位。