将表示有符号整数的字节数组转换为整数的公式

问题描述 投票:1回答:2

没有特定语言,这个问题更通用。我更感兴趣的是跨语言解决这个问题。我找到的每个答案都引用了像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或指针转换或棘手的东西)

c bit-manipulation bitwise-operators
2个回答
0
投票

按位方法仅适用于无符号值,因此您需要构建无符号整数,然后转换为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转换,因为重复没有变化。如果您也想支持其他系统,那将会更复杂。

铸件是必要的,以便在正确的宽度上进行换档。


0
投票

即使是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
© www.soinside.com 2019 - 2024. All rights reserved.