为什么在JAVA/JAVASCRIPT里要做&0xFF位运算

function dataGet(byte:Byte):Number{
    return byte&0xFF;
}

为什么要做&0xFF的位运算?

先看 源码  反码  补码,计算机内部存储的二进制码是补码。原码最高位位符号位,0表示正数,1表示负数,除非变量特别声明为unsigned类型则最高位就非符号而表示的是值(这个在JAVA/js里没有),计算机存储器和编译器之间具体怎么去转化unsigned这里不讨论,如果讨论就扯远了。一般我们讨论的都是带符号的二进制码,计算机内部存储也是带符号,只要带符号,低字节转为高字节,全部补1,切记!

  • 原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值。
  • 反码的表示方法是:正数的反码是其本身;负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。
  • 补码的表示方法是:正数的补码就是其本身;负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1。 (即在反码的基础上+1)
  • 十进制数 原码 反码 补码
    85 0101 0101 0101 0101 0101 0101
    -85 1101 0101 1010 1010 1010 1011
    9 0000 1001 0000 1001 0000 1001
    -9 1000 1001 1111 0110 1111 0111

    要想将计算机中存储的二进制码也就是补码转换成十进制数,首先得转换成原码,然后再转换成十进制数据。负数的源码转补码和补码转源码是同样的操作,除开符号位以外,其他位取反加1.再强调最高位为符号位。 

         现在来说为什么JAVA/JS里低字节转高字节要做0xFF位运算了.上面提到了unsigned这个关键字,它的意思表示无符号。而一般变量只要没有类似这unsigned特别标注的都是有符号的,那么有符号的变量在低字节转高字节时高位默认全部高位补1

         有了上面的基础,那么就说说为什么要做&0xFF了: 

//以上面9和-9为例子 ,这里Byte暂时表示比特类型一个字节,Number类型暂时代表4个字节
1.  varableByte:Byte = 9; //一个字节存储9
2.  varableNumber:Number = varableByte&0xFF;

//这里为什么不用&0xFF
3.  varableByte:Byte = -9; //一个字节存储9
4.  varableNumber:Number = varableByte;




当varableByte为正数9时,我做了&0xFF,当varableByte为负数-9时我却没做位运算。原因就是低字节转高字节高位补1,

如果编译器是原码做位运算:

9: 原码 00001001    转换成number类型后高位补1: 11111111 11111111 11111111 00001001 (请问这个的十进制值还是9吗) ,那么我赶紧补救做位运算,&0xFF的二进制补码00000000 00000000 00000000 11111111 ,运算后得到:

00000000 00000000 00000000 00001001,这个在Number类型下的二进制补码和源码正是十进制数9,这样就保持了值不变。

-9:原码 10001001    转换成number类型后高位补1: 11111111 11111111 11111111  10001001,这个做&0xFF后,

00000000 00000000 00000000 10001001,还好是-9。但我担心编译器用下面补码做位运算。

如果编译器是补码做位运算:

9: 补码 00001001    转换成number类型后高位补1: 11111111 11111111 11111111 00001001 (请问这个的十进制值还是9吗) ,那么我赶紧补救做位运算,&0xFF的二进制补码00000000 00000000 00000000 11111111 ,运算后得到:

00000000 00000000 00000000 00001001,这个在Number类型下的二进制补码和源码正是十进制数9,这样就保持了值不变。

-9:补码 11110111    转换成number类型后高位补1: 11111111 11111111 11111111  11110111,这个做&0xFF后,00000000 00000000 00000000 11110111,这十进制数还是原来的-9吗,变成正数了,哎相当无语。

 

混乱的问题来了:

   1.0xFF的二进制码为什么前面补的是0?去问你的编译器,貌似常量的16进制数据转换成二进制后前面默认补0,估计也不一定,还是要根据自己编译器去发现,真的是无语!

         2.我们做位运算后,编译器解析的是原码还是补码作运算呢?去问编译器吧。实验两次就是知道了,也许各编译器有差异,也许都是统一标准。还是让人无语!!

结语: 至少知道了为什么要&0xFF了,主要是因为在非unsigned的情况下正数在 低位转高位 值会变,为了避免值发生变化,我们才&0xFF,而如果是负数,就必须要弄清楚当前编译器是原码还是补码做位运算了,原码运算不变,补码运算会变

 

你可能感兴趣的:(编译器相关)