在一个数据处理逻辑中追踪一个bug,最后定位在一行右移运算上,结果不是预期值
var oldbyte:Byte = 0 //原字节数值
var bitcount = 1 //右移位数,下面都是用1测试
var newbyte:Byte = (oldbyte >> bitcount).toByte //新字节数值
在oldbyte>=0时一切正常
当oldbyte<0(也就oldbyte作为无符号数值>127)结果得到了非预期值
如:oldbyte = 0xfb //二进制 1111 1011,因为byte类型为有符号数,所以看到的是-5
预期右移一位后得到 0111 1101 ,即 125,结果 newbyte = -3
0xfb 二进制 1111 1011,最高位1表符号,后面是111 1011是5(_000 0101)的补码
结果-3 ,二进制 1111 1101,即最高位不是补0,而是补1
这也就是右移操作符>>,所谓的符号位扩展,高位补1
那该怎么得到预期值呢,复习了语法基础,发现另外还有一个无符号右移运算符>>>
即将原数视为无符号数,高位右移后补0,拿来试试
oldbyte = -5
newbyte = (oldbyte >>> bitcount).toByte 的结果仍为-3,似乎没起作用
通过推测以及其他网友的经验,最后得知这其中的一个【坑】
上面表达式中oldbyte,在我的理解上是一个字节的位移操作,而实际上
编译器偷偷将oldbyte转为Int类型四字节进行位移运算的,即
-5 = 1111 1111 1111 1111 1111 1111 1111 1011
最左边第一位为符号位,>>>1 运算后变为
0111 1111 1111 1111 1111 1111 1111 1101
.toByte 运算后取最低字节 1111 1101,这就是 -3
那么又该如何操作才能按字节进行无符号位移运算呢,答案是
newbyte = ( (oldbyte & 0xff) >> bitcount).toByte
oldbyte & 0xff运算,将高位三个字节都屏蔽掉,只保留低位一字节有效位
0000 0000 0000 0000 0000 0000 1111 1011
也就是得到了四字节Int表示的oldbyte原字节值0xfb,然后再做普通右移操作
0000 0000 0000 0000 0000 0000 0111 1101
最后取低字节 .toByte,就是预期值 0111 1101
参考:
https://blog.youkuaiyun.com/zxk1995/article/details/105838191