JavaScript C风格类型转换:从有符号到无符号

20

如何在JavaScript中进行数字类型转换?

a = (unsigned int)atoi(arg1);
b = (unsigned int)atoi(arg2);
假设a和b可以被标记为有符号数。
我想将一个4字节的有符号整数转换为4字节的无符号整数。
我知道在JavaScript中不存在类型转换或有符号/无符号。我正在寻找一种易于理解的算法。

你不需要在Javascript中进行类型转换。你可以直接将它作为整数使用。尽管它最初是文本。 - Mike de Klerk
JavaScript 没有有符号和无符号整数。它只有这些主要类型——文本、数字、布尔、对象、函数。 - Undefined
2
我想要将有符号数转换为无符号数。 - Matthias
@Matthias 这些4字节值的来源是什么?它们已经是ASCII十进制字符串还是4字节字节编码的字符串? - Alnitak
5个回答

50
你可以尝试a = arg1>>>0,但我不确定它是否能实现你想要的功能。
更多详情请参见此问题

4
我正是在找这个。 - Matthias
4
var arg1 = -1; var a = arg1>>>0 alert(a); - Matthias
非常感谢您提供的解决方案。通过这种方法,我能够以更优雅的方式解决https://dev59.com/XYfca4cB1Zd3GeqPot9M的问题。 - ptdecker
当我尝试执行-5 >>> 0时,为什么会得到4294967291? - codemirror
1
作为一个带符号的32位整数,-5看起来像11111111111111111111111111111011,当解释为无符号整数时,它是4294967291。在无符号整数运算中,0减去5得到的结果就是这个。 - Vatev

17
您也可以使用
(new Uint32Array([arg1]))[0]

e.g.

< (new Uint32Array([-1]))[0]
> 4294967295

解释: JavaScript不像C语言那样遵循传统的机器架构整数转换约定,而是更喜欢类型简单性和可移植性,而JavaScript中的类型化数组(Uint8Array等)是专门为了实现高效和良好定义的多字节和位级操作而添加的。 因此,我们可以利用这个事实来访问良好定义和内置的位转换操作。上面例子中的语法:
  1. 创建输入的自然数数组
  2. 从该数字构造一个类型化数组(Uint32Array)。这是将进行强制转换的地方。
  3. 提取该类型化数组的第一个(0号)元素,其中包含转换结果。

1
关于“魔法”部分。计算机中的数据以比特表示,一个字节是8个比特。 要创建负数,您将最后一位设置为1。这意味着您有7位来存储您的数字(如果将最后一位设置为0,则有7位来存储正值,或者如果将最后一位设置为1,则有7位用于表示负数)。这意味着没有什么神奇之处,您只需告诉编译器如何理解该值即可。例如,如果将其视为已签名数字,则可以将正数视为负数。( U表示无符号的Uint32) - David Gatti
迟来的补充解释。 - joth

8

将有符号字节转换为无符号字节,JavaScript:

-5 & 0xff // = 251   , signed to unsigned byte
251 <<24 >>24 // = -5  , unsinged byte to signed

第一个操作将除了第一个字节之外所有的第一个位都变成0

第二个操作可以在以下链接中找到:

https://blog.vjeux.com/2013/javascript/conversion-from-uint8-to-int8-x-24.html

简单来说,一个数字有4个字节。对于正数来说,前3个字节是0,并且所有的0比特都是0。对于负数来说,前3个字节是1,并且所有的0比特都是1,而所有的1比特都是0。在字节中,第4个字节的最高比特用于表示符号;

将比特向左移动使得第一个字节的第一个比特变为第四个字节的第一个比特,然后再向右移动,就可以拖动最高有效比特。所以如果符号比特为1,则会在前3个字节中产生许多1比特。因此这是一个移位的副作用,但它起作用。

for example: like you start from
?1111111 the first bit is a sign bit - ?, 
but in a larger variable,  so it is:

00000000_00000000_00000000_?1111111
shift to left
?1111111_........_........_........
shift to right
????????_????????_????????_?1111111
this is the effect,
it drags the edge bit across the shift

4

Javascript中的所有(原始)数字都是IEEE748双精度浮点数,提供了52位整数精度。

有符号和无符号的问题在于,除了>>>之外的所有Javascript位运算符都将数字转换为32位的有符号数字——也就是说,它们取最低有效32位并且舍去其余部分,然后将结果的第31位作为符号扩展以给出带符号的结果。

如果您从已知的四个字节值开始,则可以通过使用简单的乘法和加法来绕过位运算符的问题,这些运算符使用了所有52位的整数精度,例如:

var a = [ 1, 2, 3, 4];  // 0x01020304
var unsigned = a[0] * (1 << 24) + a[1] * (1 << 16) + a[2] * (1 << 8) + a[3]

1

TypedArray可以使这个过程变得更容易:

const int32SignedToUnsigned = (int32) => Uint32Array.from(Int32Array.of(int32))[0];
const int32UnsignedToSigned = (uint32) => Int32Array.from(Uint32Array.of(uint32))[0];

// Examples:
 
console.log('with expected inputs:')
console.log(int32SignedToUnsigned(-1))
console.log(int32UnsignedToSigned(4294967295))
console.log(int32SignedToUnsigned(-2))
console.log(int32UnsignedToSigned(4294967294))

console.log('overflow behavior:')
console.log('int32UnsignedToSigned(4294967296):', int32UnsignedToSigned(4294967296))
console.log('int32SignedToUnsigned(4294967296):', int32SignedToUnsigned(4294967296))
console.log('int32UnsignedToSigned(-1):', int32UnsignedToSigned(-1))
console.log('int32SignedToUnsigned(-1):', int32SignedToUnsigned(-1))

请注意,如果提供的输入实际上不在Uint32或Int32范围内,则每个函数的行为。
来源:Libauth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接