问题
I'm doing some bitwise manipulation in a project and I wonder if the built-in typed arrays might save me some headache and maybe even give me a bit of a performance gain.
let bytes = [128, 129, 130, 131]
let uint32 = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]
//=> -2138996093
Can I use typed arrays to get the same answer ?
// not actually working !
let uint8bytes = Uint8Array.from(bytes)
let uint32 = Uint32Array.from(uint8bytes)[0]
//=> ideally i'd get the same value as above: -2138996093
Side question:
I found it strange that the uint32
above is negative – obviously not very ... unsigned as the name of the var suggests ...
If I mash together binary octets and parse it, I get the complimentary positive answer
// 128 129 130 131
let bin = '10000000' + '10000001' + '10000010' + '10000011'
let uint32 = Number.parseInt(bin,2)
console.log(uint32)
// 2155971203
It's no surprise that I can reverse the process to get the correct values out of each, but I don't understand why procedure 1 is negative but procedure 2 is positive.
let a = -2138996093;
let b = 2155971203;
// two's compliment, right?
console.log(a.toString(2)) // -1111111011111100111110101111101
console.log(b.toString(2)) // 10000000100000011000001010000011
console.log(a >> 24 & 255) // 128
console.log(a >> 16 & 255) // 129
console.log(a >> 8 & 255) // 130
console.log(a >> 0 & 255) // 131
console.log(b >> 24 & 255) // 128
console.log(b >> 16 & 255) // 129
console.log(b >> 8 & 255) // 130
console.log(b >> 0 & 255) // 131
回答1:
The best way to handle this is with a DataView - that way you can specify the endianness of the value you want to get - your code is using bigendian values for the int32
let bytes = [128, 129, 130, 131];
let uint8bytes = Uint8Array.from(bytes);
let dataview = new DataView(uint8bytes.buffer);
let int32le = dataview.getInt32(0, true); // second parameter truethy == want little endian
let int32be = dataview.getInt32(0); // second parameter absent or falsey == want big endian
console.log(int32le); // -2088599168
console.log(int32be); // -2138996093
The reason
let uint32 = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]
returns a SIGNED int is that the bitwise operators (<<
, |
) coerce the values to a signed 32 bit value
来源:https://stackoverflow.com/questions/39422506/is-it-possible-to-convert-from-4x-uint8-into-uint32-using-typed-arrays-in-javasc