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

时间:2019-03-19 02:31:57

标签: c bit-manipulation bitwise-operators

这个问题在没有特定语言的情况下更为通用。我对跨语言解决这个问题更感兴趣。我发现的每个答案都引用了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补码的信息,这使我进入了Wikipedia的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)中,移位可能会使int值溢出。

这很难搜索,因为我得到了一千个解释大尾数法和小尾数法之间的区别的结果,或者解释了二进制补码的结果,还有更多给出使用标准库的示例,但我还没有看到完整的例子。位函数的公式。

是否有C或类似语言的规范示例,仅使用数组访问和按位函数(即,没有memcpy或指针转换或棘手的东西)来转换char数组

2 个答案:

答案 0 :(得分:0)

按位方法仅适用于无符号值,因此您将需要构建无符号整数,然后转换为有符号。代码可能是:

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转换定义为表示形式不变。如果您也想支持其他系统,那就更复杂了。

必须进行强制转换,以便在正确的宽度上执行移位。

答案 1 :(得分: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