位移溢出问题

来源:互联网 发布:护肤品推荐 知乎 编辑:程序博客网 时间:2024/05/21 07:14

“    今天调试程序,调出来个问题,就是左移溢出的问题。

unsigned short COM_BUFB[2048];

if( !( ((COM_BUFB[k+1]<<16) + COM_BUFB[k] ) == 0 || ((COM_BUFB[k+1]<<16) +COM_BUFB[k])==0xfffffff7 ) )

其中,COM_BUFB是个16位的数组,COM_BUFB[k+1]<<16的结果就是0了。遂,错误。”

 

以前想法有些错误,经过在csdn的请教与探讨(csdn页面连接),发现这是个MDK的显示bug。

 

接下来说一下真正的关于位移的溢出:
知识点:  ①移位比乘除的效率要高:
              ②算术位移:会保持符号位不变,右移是算数位移。
              ③逻辑位移:不会保持符号位不变,对于左移,算术左移和逻辑左移是完全相同的。


以左移为例,左移就是把一个数的所有位都向左移动若干位,在C中用<<运算符,需要注意的有两点:

1、int类型最左端的符号位和移位移出去的情况.我们知道,int是有符号的整形数,最左端的1位是符号位,即0正1负,那么移位的时候就会出现溢出,例如:
int i = 0x40000000; //16进制的40000000,为2进制的01000000...0000
i = i << 1;
那么,i在左移1位之后就会变成0x80000000,也就是2进制的100000...0000,符号位被置1,其他位全是0,变成了int类型所能表示的最小值,32位的int这个值是-2147483648,溢出.如果再接着把i左移1位会出现什么情况呢?在C语言中采用了丢弃最高位的处理方法,丢弃了1之后,i的值变成了0.

2、左移里还有一个比较特殊的情况是当左移的位数超过该数值类型的最大位数时,编译器(GCC)会用左移的位数去模类型的最大位数,然后按余数进行移位,如:
int i = 1, j = 0x80000000; //设int为32位
i = i << 33;    // 33 % 32 = 1 左移1位,i变成2
j = j << 33;    // 33 % 32 = 1 左移1位,j变成0,最高位被丢弃
在用gcc编译这段程序的时候编译器会给出一个warning,说左移位数>=类型长度.那么实际上i,j移动的就是1位,也就是33%32后的余数.在gcc下是这个规则,别的编译器是不是都一样现在还不清楚.