原文地址

Javascript 16进制转有符号的10进制整数

前言

今天做小程序开发,需要将对应蓝牙特征值中的数据(十六进制字符串)转化为十进制数。

var a = "F831";
console.log("####->"+parseInt(a,16));

发现0xF831转换为十进制后,结果却是63537。但在底层开发中,数据类型为int16_t(有符号 2字节)。转换的完全对不上呀!

正文

朋友推荐一篇参考博客。下面为转载内容。

这里我们就需要温习一下数据在底层的转换,我们都知道数据在计算机里都是用二进制形式存储的。有符号的整数有两种方式存储,一种正数存储,一种负数存储。正数存储就是以真二进制的方式,最高位为0,后面每一位都表示2的幂次。而负数则麻烦的多,它采用二进制补码的形式存储。确定一个负数的二进制需要三步:

  • 1、确定该数字的绝对值的二进制,因为是负数所以最高位的“0”改为“1”,其为原码。
  • 2、将该绝对值,除了最高位的符号位外其他位的“0”替换成“1”,“1”替换成“0”,这就是二进制的反码。
  • 3、反码加上1,确定其补码。

比如-256转换为二进制,具体步骤如下:

  • 1.先将256转换为二进制数为1 0000 0000,因位数不是8的倍数,需要在不足的高位补上0,得0000 0001 0000 0000。因为-256是负数,所以最高位改为1000 0001 0000 0000。
  • 2.再将除了符号位其他位的1和0对换,得1111 1110 1111 1111。
  • 3.把反码加上1得1111 1111 0000 0000。

现在再把它转为16进制,就得到上面我们一开始的“FF00”了。

ps:看到一个关于负数为什么是用补码存储的有趣说法,说计算机喜欢加法,正数的二进制和负数的二进制相加得0,这样极大减少了内存占用。

具体分析

首先先定义一个变量:

var i = "F831";

JavaScript只提供了2-32进制转换为10的函数,和10进制转换为2-32的方法,所以我们要把一个16进制转换为2进制需要使用其10进制作为中间量。

let two = parseInt(i, 16).toString(2);

再求出变量应有的位数,在不足的位数上补“0”。

let bitNum=i.length*4;
if (two.length < bitNum) {
  while (two.length < bitNum) {
    two = "0" + two;
  }
}

判断它的最高位是否是0,如果是,转换为10进制后原样输出。

if (two.substring(0, 1) == "0") {
  two = parseInt(two, 2);
}

如果不是,按照之前提供的步骤处理一下。

else {
	let two_unsign = "";
	two = parseInt(two, 2) - 1;//减一
	two = two.toString(2);
	two_unsign = two.substring(1, bitNum);//截取除了最高位以外的位
	two_unsign = two_unsign.replace(/0/g, "z");//反码
	two_unsign = two_unsign.replace(/1/g, "0");
	two_unsign = two_unsign.replace(/z/g, "1");
	two = parseInt(-two_unsign, 2);//补上负号
}

我们封装一下。

module.exports=(i)=>{
  let two = parseInt(i, 16).toString(2);
  let bitNum=i.length*4;
  if (two.length < bitNum) {
    while (two.length < bitNum) {
      two = "0" + two;
    }
  }
 
  if (two.substring(0, 1) == "0") {
    two = parseInt(two, 2);
 
    return two;
  } else {
    let two_unsign = "";
    two = parseInt(two, 2) - 1;
    two = two.toString(2);
    two_unsign = two.substring(1, bitNum);
    two_unsign = two_unsign.replace(/0/g, "z");
    two_unsign = two_unsign.replace(/1/g, "0");
    two_unsign = two_unsign.replace(/z/g, "1");
    two = parseInt(-two_unsign, 2);
 
    return two;
  }
}

js定义funtion

function hex2int(hexStr) {
  let twoStr = parseInt(hexStr,16).toString(2); // 将十六转十进制,再转2进制
  let bitNum = hexStr.length * 4; // 1个字节 = 8bit ,0xff 一个 "f"就是4位
  if(twoStr.length < bitNum){
    while(twoStr.length < bitNum){
      twoStr = "0" + twoStr;
    }
  }
  if(twoStr.substring(0,1) == "0"){
    // 正数
    twoStr = parseInt(twoStr,2); // 二进制转十进制
    return twoStr;
  }else{
    // 负数
    let twoStr_unsign = "";

    console.log("hex2int--->"+parseInt(twoStr,2));
    twoStr = parseInt(twoStr,2) - 1; // 补码:(负数)反码+1,符号位不变;相对十进制来说也是 +1,但这里是负数,+1就是绝对值数据-1
    console.log("hex2int--->"+twoStr);

    twoStr = twoStr.toString(2);
    twoStr_unsign = twoStr.substring(1,bitNum); // 舍弃首位(符号位)
    // 去除首字符,将0转为1,将1转为0   反码
    twoStr_unsign = twoStr_unsign.replace(/0/g, "z");
    twoStr_unsign = twoStr_unsign.replace(/1/g, "0");
    twoStr_unsign = twoStr_unsign.replace(/z/g, "1");
    
    console.log("hex2int--->"+twoStr_unsign);
    console.log("hex2int--->"+(-twoStr_unsign));
    twoStr = parseInt(-twoStr_unsign, 2);
    return twoStr;
  }
}

测试

var a = "F831";
console.log("####->"+hex2int(a));

在这里插入图片描述

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐