Reputation: 8479
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
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
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