我正在用 JavaScript 开发 CRC32 算法,对此我还很陌生。 一切似乎都很顺利,直到最后一步:将校验和与 0xFFFFFFFF 进行异或。
1001010100111101101100010001000
^ 11111111111111111111111111111111 = -1001010100111101101100010001001
1251924104 ^ 4294967295 = -1251924105
负值似乎是个问题。我可以做什么来解决这个问题?
Javascript 中的按位运算会将数字强制转换为带符号的 32 位整数,最大值为
2^31-1
。您的号码,0xFFFFFFFF
,是 2^32-1
。
但是,如果您使用 BigInts 来代替,它会正常工作:
console.log(0xFFFFFFFF ^ 0)
console.log(String(0xFFFFFFFFn ^ 0n))
注意:我必须使用
String()
,因为 stackoverflow console.log 函数似乎无法处理 BigInts。
JavaScript 中的大多数按位运算符都会对带符号的 32 位整数进行运算并返回其结果(只要操作数是普通数字,而不是 bigint)。 然而,有一个运算符不这样做:无符号右移运算符
>>>
,它返回一个 无符号 32 位整数。
您可以使用无符号零右移将有符号 32 位整数强制转换为无符号 32 位整数:
console.log(~0);
console.log(~0 >>> 0);
console.log(1251924104 ^ 0xffffffff);
console.log((1251924104 ^ 0xffffffff) >>> 0);
// since JS bitwise operators work on 32-bit values,
// bitwise negation is equivalent to XORing with 0xffffffff
console.log(~1251924104);
console.log(~1251924104 >>> 0);
从第一个 JavaScript 版本(如 Netscape 2.02)开始就支持
>>>
运算符,这与仅出现在 ECMAScript 2020(ECMA-262 第 11 版)中的 bigint 支持不同。 因此,您应该更喜欢它而不是 bigint,特别是如果您没有使用后者,因为这将确保更好的兼容性。
无论如何,问题大部分是表面上的。 无论这些值被解释为有符号整数还是无符号整数,应用按位运算符产生的位模式都是相同的。 因此,仅在显示结果时,或者在将结果作为操作数输入算术(非按位)运算符之前应用无符号强制就足够了,而这种解释实际上很重要。