没有特定语言,这个问题更通用。我更感兴趣的是跨语言解决这个问题。我找到的每个答案都引用了像getInt32
这样的内置方法来从字节数组中提取整数。
我有一个字节数组,其中包含有符号整数的big-endian表示。
1 -> [0, 0, 0, 1]
-1 -> [255, 255, 255, 255]
-65535 -> [255, 255, 0, 1]
获得积极案例的价值很容易:
arr[3] | arr[2] << 8 | arr[1] << 16 | arr[0] << 24
我想弄清楚的是更一般的情况。我一直在阅读有关2s补码的内容,它引导我从维基百科的python函数:
def twos_complement(input_value, num_bits):
'''Calculates a two's complement integer from the given input value's bits'''
mask = 2**(num_bits - 1) - 1
return -(input_value & mask) + (input_value & ~mask)
这反过来导致我产生这个功能:
# Note that the mask from the wiki function has an additional - 1
mask = 2**(32 - 1)
def arr_to_int(arr):
uint_val = arr[3] | arr[2] << 8 | arr[1] << 16 | arr[0] << 24
if (determine_if_negative(uint_val)):
return -(uint_val & mask) + (uint_val & ~mask)
else:
return uint_val
为了让我的功能工作,我需要填写determine_if_negative
(我应该屏蔽已签名的位并检查它是否为1)。但有没有一个标准的公式来处理这个?我发现的一件事是,在某些语言中,比如Go,bitshift可能会溢出int值。
这很难搜索,因为我得到了一千个结果,解释了big-endian和little-endian之间的区别或结果解释了二进制补码,还有更多给出了使用标准库的例子,但是我还没有看到完整的按位公式功能。
在C或类似语言中是否存在仅使用数组访问和按位函数转换char数组的规范示例(即,没有memcpy或指针转换或棘手的东西)
按位方法仅适用于无符号值,因此您需要构建无符号整数,然后转换为signed。代码可以是:
int32_t val( uint8_t *s )
{
uint32_t x = ((uint32_t)s[0] << 24) + ((uint32_t)s[1] << 16) + ((uint32_t)s[2] << 8) + s[3];
return x;
}
注意,这假设您使用2的补码系统,该系统还定义了unsigned-> signed转换,因为重复没有变化。如果您也想支持其他系统,那将会更复杂。
铸件是必要的,以便在正确的宽度上进行换档。
即使是c也可能是太高级了。毕竟,int的确切表示取决于机器。最重要的是,并非所有系统上的所有整数类型都是2s补码。
当您提到字节数组并将其转换为整数时,您必须指定字节数组所暗示的格式。
如果你假设2s补码和小端(如intel / amd)。然后最后一个字节包含符号。
为简单起见,我们先从4位2s补码整数开始,然后是字节字节,然后是2字节整数,然后是4。
BIN SIGNED_DEC UNSIGNED_DEC
000 0 0
001 1 1
010 2 2
100 -4(oops) 4
101 -3 5
110 -1 6
111 -1 7
---
123
让每个位为b3,b2,b1,其中b1是最高有效位(和符号),则公式为:
b3*2^2+b2*2^1-b1*4
对于一个字节,我们有4位,公式如下所示:
b4*2^3 + b3*2^2+b2*2^1-b1*2^3
对于2个字节,它是相同的但我们必须将最高有效字节乘以256,而负值将是256 ^ 2或2 ^ 16。
/**
* returns calculated value of 2s complement bit string.
* expects string of bits 0or1. if a chanracter is not 1 it is considered 0.
*
*/
public static long twosComplementFromBitArray(String input) {
if(input.length()<2) throw new RuntimeException("intput too short ");
int sign=input.charAt(0)=='1'?1:0;
long unsignedComplementSum=1;
long unsignedSum=0;
for(int i=1;i<input.length();++i) {
char c=input.charAt(i);
int val=(c=='1')?1:0;
unsignedSum=unsignedSum*2+val;
unsignedComplementSum*=2;
}
return unsignedSum-sign*unsignedComplementSum;
}
public static void main(String[] args) {
System.out.println(twosComplementFromBitArray("000"));
System.out.println(twosComplementFromBitArray("001"));
System.out.println(twosComplementFromBitArray("010"));
System.out.println(twosComplementFromBitArray("011"));
System.out.println(twosComplementFromBitArray("100"));
System.out.println(twosComplementFromBitArray("101"));
System.out.println(twosComplementFromBitArray("110"));
System.out.println(twosComplementFromBitArray("111"));
}
输出:
0
1
2
3
-4
-3
-2
-1