【问题标题】:Convert binary data to signed integer将二进制数据转换为有符号整数
【发布时间】:2011-10-18 16:37:52
【问题描述】:

我读取了一个二进制文件并获得了一个包含字符的数组。将两个字节转换为整数时,我会使用256*ord(p1) + ord(p0)。它适用于正整数,但当我得到一个负数时它不起作用。我知道最高有效字节中有第一位但没有成功。

我也知道有一个叫做struct的东西,读完后我得到了以下代码

import struct

p1 = chr(231)
p0 = chr(174)

a = struct.unpack('h',p0+p1)

print str(a)

a 变为 -6226,如果我交换 p0p1 我得到 -20761。

a 应该是 -2

【问题讨论】:

    标签: python


    【解决方案1】:

    -2 对于您指定的值不正确,并且字节顺序很重要。 struct> 用于大端(最高有效字节在前),< 用于小端(最低有效字节在前):

    >>> import struct
    >>> struct.pack('>h',-2)
    '\xff\xfe'
    >>> struct.pack('<h',-2)
    '\xfe\xff'
    >>> p1=chr(254) # 0xFE
    >>> p0=chr(255) # 0xFF
    >>> struct.unpack('<h',p1+p0)[0]
    -2
    >>> struct.unpack('>h',p0+p1)[0]
    -2
    

    【讨论】:

      【解决方案2】:

      通常,在使用 struct 时,您的格式字符串应以 alignment specifiers 之一开头。默认的本机版本因机器而异。

      因此,正确的结果是

      >>> struct.unpack('!h',p0+p1)[0]
      -20761
      

      endian中-2的表示为:

      1111 1111 1111 1110 # binary
        255        254    # decimal bytes
        f   f    f    e   # hexadecimal bytes
      

      您可以通过添加两个轻松验证这一点,结果为 0。

      【讨论】:

        【解决方案3】:

        使用第一种方法(256*ord(p1) + ord(p0)),您可以使用if p1 &amp; 0x80 &gt; 0 检查第一位是否为 1。如果是这样,那么您将使用p1 &amp; 0x7f 而不是p1,然后否定最终结果。

        【讨论】:

          【解决方案4】:

          作为记录,您可以在没有struct 的情况下执行此操作。可以用你原来的等式,但是如果结果大于32767,就减去65536。(或者如果高位字节大于127,也是一样的。)查找二进制补码,所有现代计算机都是这样表示负整数。

          p1 = chr(231)
          p0 = chr(174)
          
          a = 256 * ord(p1) + ord(p0) - (65536 if ord(p1) > 127 else 0)
          

          这将为您提供 -6226 的正确答案。 (正确答案不是-2。

          【讨论】:

            【解决方案5】:

            如果要转换大文件中的值,请使用 array 模块。

            对于文件,要知道文件格式的字节顺序很重要。不是编写它或正在阅读它的机器的字节序。

            当然,Alex Martelli 有the definitive answer

            【讨论】:

              【解决方案6】:

              如果您使用掩码去除负数中的额外1 位,您的原始方程式将可以正常工作:

              256*(ord(p0) & 0xff) + (ord(p1) & 0xff)
              

              编辑:我想我可能误解了你的问题。您正在尝试将两个正字节值转换为负整数?这应该有效:

              a = 256*ord(p0) + ord(p1)
              if a > 32767: # 0x7fff
                  a -= 65536 # 0x10000
              

              【讨论】:

              • 因为这些已经是 8 位的量,所以屏蔽低 8 位并没有任何作用。
              • 要屏蔽符号位,你会使用&amp; 0x7F,不是吗?
              • @kindall,最初的问题是负数。负数是符号扩展的,因此高位包含1 而不是0,因此需要屏蔽它们。不过,我仍然不太确定 ord 如何返回负数。
              • @Colt45,如果您使用&amp; 0x7f,您将丢失第 8 位。您不想删除符号位,而是想删除其左侧的扩展。
              • 'ord()' 不返回负数——他试图解码的两字节数是负数。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-11-30
              • 1970-01-01
              • 2020-11-26
              • 1970-01-01
              • 1970-01-01
              • 2015-05-02
              相关资源
              最近更新 更多