2.1. C语言中的移位运算
这里有两种移位操作:算术移位和逻辑移位,其主要差别在于有符号数的负数上。
对于x=00110011而言 y=x>>3
* 逻辑移位 y=00000110
* 算术移位 y=00000110
对于x=10110011而言 y=x>>3
- 逻辑移位 y=00010110
- 算术移位 y=11110110
也就是说:算术右移是在最左端补k个最高有效位的值,而逻辑移位统一补0。
在C语言中,对于无符号数,统一采用逻辑移位,对于有符号数,大部分编译器采用算术移位。这样对有符号整数的运算非常有帮助。请保证移位的数量小于计算机存储的字长。
2.2 整数表示
w位2进制数
无符号整数范围
2w−1
到 0
有符号整数范围
2w−1−1
到
−2w−1
java中全部都是有符号数
补码的表示
即将字的最高位解释为负权
注意,补码对于任意一个数都是唯一表示的。
在C与java中数的表示范围的差别
- C中各种类型的表示范围定义在
<
limits.h>
中,包括INT_MAX INT_MIN 以及UINT_MAX。 而在<
stdint.h>
定义了与实现有关的类型, 包含uint16_t之类的,这样在一定成都上避免了移植的问题。 - java中不存在移植的问题,不管在什么机器上,其表示的范围与标准64位机器的类型字长一致。
有符号数和无符号数之间的互相转换
对于大多数C语言的实现来说,处理同样字长的有符号数和无符号数之间的转换规则是:数值可能改变,但是在系统内存储的位模式不变。在数值上的改变是:
非负数不变,负数转变为大的正数(+
2w
)
2.3 无符号数截断的结果
- 原本w位的无符号数变为k位,数值上
B2Uk[xk−1,xk−2,……,x0]=B2Uw([xw−1,xw−2,……,x0])modxk - 补码数字的截断结果是
B2Tk[xk−1,xk−2,……,x0]=B2Tk(B2Uw([xw−1,xw−2,……,x0])modxk)
也就是说,先要按无符号数的形式截断一次,之后再把截断的结果转换位补码
2.4 关于这部分的应用(我的一点理解)
float sum(float a[], unsigned int length)
{
int i;
float result=0;
for(i=0;i<=length-1;i++)
result += a[i];
return result;
}
当我们给length 赋值0的时候,运行这段代码本应该产生0.0,但是实际运行会出现数组越界的问题,原因如下:
length位无符号数,在执行i<=length-1
的时候,length-1会自动转为int类型,首先length-1变为-1,-1由unsigned int转为int 需要加
2w
之后与i比较,所以数组要越界。
建议
1.大部分时候,我们不要使用无符号数,因为程序之间存在的隐式有符号数向无符号数的转换会导致错误和漏洞,我们所有的遍历都用有符号数去解决,多加一些数组越界的判断。
2.对于我们仅仅把字看做位的集合,没有任何数字意义的时候,比如我们利用位作为标志flag的时候,或者作为地址的时候,我们可以采用无符号数,这样也更加直观