十六进制格式的带符号二进制转十进制
这个问题必须记录一下,我以为转换就是直接按位取反,但是结果总是不对,经过分析后才发现数据分析就有问题,那当然接下来怎么做都不会对了
计算方法
我们先演示流程并获取结果:
0xFFF8
转 二进制:1111 1111 1111 1000
,这是带符号的二进制数据,首位为 1 ,因此是负数;- 负数是用补码表示的,补码是原码取反+1,也就是说需要先减 1 得到:
1111 1111 1111 0111
; - 取反得到:
0000 0000 0000 0000 1000
,转10进制就是8
,加上符号就是-8
,没错,这就是我想要的结果。
~
操作符转换演示
$a = 0xFFF8;
$ret = ~$a;
var_dump($ret); // 输出:-65529
结果和我想要的不一样啊,那来捋一下 ~
操作符的计算流程,我们用简单的值演示一下:
0x0005
转 二进制:0000 0000 0000 0101
;- 取反得到:
1111 1111 1111 1010
, 观察取反后的结果,从左向右看,第一位 0正1负; - 负数是用补码表示的,补码是除符号位外按位取反+1,也就是说
1111 1111 1111 1010
是某个数取反+1得到的,反过来,也就是先 -1,结果是:1111 1111 1111 1001
; - 取反得到:
1000 0000 0000 0110
,转10进制就是-6
。
看过上面的流程就可以发现啦,一直以为0xFFF8
是原数,所以就作按位取反,当然结果一直不对,因为转换方式和数据分析 都是错的,数据是从硬件内存中取出直接上传的,而负数在内存中以补码形式存在,因此数据已经是补码了,再按位取反当然就不对了。
正确转换方式
$a = 0xFFF8;
$ret = $a - 0xFFFF - 1;
var_dump($ret); // 输出:-8
没错,就是这么简单!当然,这个是针对 2字节的数据的,如果是4字节,将 0xFFFF
改为 0xFFFFFFFF
就可以啦~
当然,以上纯粹针对小白。。。