alexbuisson
alexbuisson

Reputation: 8479

How to interpret (read) signed 24bits data from 32bits

I have raw file containing signed 24bits data packed into 32bits example:

00 4D 4A FF 
00 FF FF FF

I would like read those data and get signed integer between [-2^23 and 2^23-1]

for now I write

  int32_1 = file1.read(4)
  val1 = (( unpack('=l', int32_1)[0] & 0xFFFFFF00)>>8

but how to take the 2-complement into account to interpret 00FFFFFF as -1 ?

Upvotes: 1

Views: 62

Answers (2)

PM 2Ring
PM 2Ring

Reputation: 55499

Your code is making things more complicated than they need to be. However, you really should specify the endian type correctly in the unpack format string.

from binascii import hexlify
from struct import unpack

data = ('\x00\x03\x02\x01', '\x00\x4D\x4A\xFF', '\x00\xFF\xFF\xFF')

for b in data:
    i = unpack('<l', b)[0] >> 8
    print hexlify(b), i

output

00030201 66051
004d4aff -46515
00ffffff -1

FWIW, here's a version that works in Python 3 or Python 2; the output is slightly different in Python 3, since normal strings in Python 3 are Unicode; byte strings are "special".

from __future__ import print_function
from binascii import hexlify
from struct import unpack

data = (b'\x00\x03\x02\x01', b'\x00\x4D\x4A\xFF', b'\x00\xFF\xFF\xFF')

for b in data:
    i = unpack('<l', b)[0] >> 8
    print(hexlify(b), i)    

Python 3 output

b'00030201' 66051
b'004d4aff' -46515
b'00ffffff' -1

And here's a version that only runs on Python 3:

from binascii import hexlify

data = (b'\x00\x03\x02\x01', b'\x00\x4D\x4A\xFF', b'\x00\xFF\xFF\xFF')

for b in data:
    i = int.from_bytes(b[1:], 'little', signed=True)
    print(hexlify(b), i)

Upvotes: 2

PA.
PA.

Reputation: 29369

you can shift 8 bits to the left, take the result as a signed 32bit integer (use ctypes library), and divide by 256

>>> import ctypes
>>> i = 0x00ffffff
>>> i
16777215
>>> i<<8
4294967040
>>> ctypes.c_int32(i<<8).value
-256
>>> ctypes.c_int32(i<<8).value//256
-1

Upvotes: 1

Related Questions