侧边栏壁纸
  • 累计撰写 218 篇文章
  • 累计创建 59 个标签
  • 累计收到 5 条评论

& 0xFF

barwe
2022-04-29 / 0 评论 / 0 点赞 / 1,078 阅读 / 1,858 字
温馨提示:
本文最后更新于 2022-04-29,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

做项目时需要将 Excel 工作簿写入文件,遂在网上找到了这样一段代码:

const wbout = XLSXStyle.write(workbook, {
  bookType: 'xlsx',
  bookSST: false,
  type: 'binary',
})
const buf = new ArrayBuffer(wbout.length)
const view = new Uint8Array(buf)
for (let i = 0; i !== wbout.length; ++i) {
  view[i] = wbout.charCodeAt(i) & 0xff
}
const blob = new Blob([buf], { type: '' })
saveAs(blob, filename)

其中 xlsx-style 包将 WorkBook 对象转换成了一个 binary string,然后将其数据转存到 unsign int8 数组中。转存时通过charCodeAt获取每个字符的 UTF-16 编码,然后与0xff做与运算后,才存入 Uint8 数组中。这样最终就得到了一个 Uint8 类型的数组,然后将其写入 xlsx 文件。那么为什么要与0xff做与运算呢?经过研究后发现,这应该与计算机对数字的存储有关。

0xff对应的二进制数是0b1111_1111,需要与0xff一般发生在低字节整数向高字节整数转换时,例如 byte 类型转为 int16 类型。

在此之前,我们先简单复习一下计算机的二进制存储特点。

计算机在存储负数时实际上存储的是其对应正数的二进制形式的补数。以 byte 类型为例,计算机将 1 存储为 0000 0001,这个二进制数的补数是 1111 1111,因此 -1 在计算机中的存储形式实际为 1111 1111。

当进行像 byte 类型转换为 int16 类型时,需要在高位字节进行填充,计算机默认使用符号位填充所有高位:

  • 正数例如 0000 0001 填充后变为 0000 0000 0000 0001
  • 负数例如 1111 1111 填充后变为 1111 1111 1111 1111

全填充符号位有什么好处呢?二进制数虽然变了(对负数的转换而言),但是它们对应的十进制数不会发生变化!因为不管填充多少位,正数的二进制始终在高位填 0,它的二进制值不会发生变化,而负数的二进制形式始终是对应正数的二进制值的补数,原数不变,模变了,补数自然就变了

全填充符号位能保证转换前后数的十进制真实值不发生变化,尤其是对于负数而言。保持真实值的一致性势必会导致计算机存储的负数的补码发生变化。然而我们并不是所有情况下都需要在类型转换中保持真实值的一致性,例如对文件流进行转换,我们需要保证的是字节的二进制值在转换前后保持一致,对于正数其实没有影响,但对于负数而言 1111 1111 转换成 1111 1111 1111 1111其实就已经改变了字节的二进制值(但是十进制没有改变)。不改变二进制值的转换方式时将其变成 0000 0000 1111 1111,这样转换前后十进制值会发生变化,但是 保证了补码的一致性

总而言之,在需要数值参与计算时,我们需要保证真实值(即十进制值)的一致性,在转换文件流这种数据时需要保证字节二进制值(即补码)的一致性。那么怎么保证二进制值的一致性呢?答案就是上面提到的与0xff做与运算。

0xff本身是一个字面量值,它在 JS 里面是一个无符号整数,当向多字节转换时它会默认在高位填充 0

  • 1 从 byte 转换为 int16:0000 00010000 0000 0000 0001 & 0000 0000 1111 11110000 0000 0000 0001
  • -1 从 byte 转换为 int16:1111 11111111 1111 1111 1111 & 0000 0000 1111 11110000 0000 1111 1111

上面的例子中 wbout 是一个 binary string,charCodeAt每次取出一个字符的 UTF-16 编码值。

这里不太理解 wbout 具体内容是什么,看代码是取出每个字节与上0xff,说明charCodeAt取出的结果总是小于 256?不然怎么敢与0xff

但是0xff的作用算是学习到了,两字节的 UTF-16 码点为什么与上0xff以后再思考。

参考资料

https://www.cnblogs.com/think-in-java/p/5527389.html

https://barwe.cc/2022/04/29/computer-negative-number

https://github.com/markatil/xlsx-style#writing-workbooks

0

评论区