I feel like this should be simple, and because it's so simple, I can't wrap my head around why it's not working.
I have a basic function that uses struct.unpack to turn a bytearray into an integer. So we can see that in hex notation x90 = 144 in decimal. So I would expect that if I ask unpack to convert to integer, I get 144, but I'm getting this ridiculously large number. I'm happy to read whatever reference material you can provide, as the struct documentation does not provide any clues.
See example below:
unpack_signed_integer, = struct.unpack('i', b'\x00\x00\x00\x90')
unpack_unsigned_integer, = struct.unpack('I', b'\x00\x00\x00\x90')
print(f"signed integer: {unpack_signed_integer}")
print(f"unsigned integer: {unpack_unsigned_integer}")
Output:
signed integer: -1879048192
unsigned integer: 2415919104
2 Answers 2
You are unpacking the value 0x90_00_00_00, that is, a 64 bit number in little-endian order. It is large because it has 7 hexadecimal zeros, each representing a power of sixteen.
Either reverse the order of your bytes, or pick a different byte order:
>>> import struct
>>> struct.unpack('I', b'\x00\x00\x00\x90')
(2415919104,)
>>> struct.unpack('I', b'\x90\x00\x00\x00')
(144,)
>>> struct.unpack('>I', b'\x00\x00\x00\x90')
(144,)
In the above example, the > in '>I' tells struct.unpack() to use big-endian ordering instead. If you are dealing with data you received from some network protocol, you should probably use ! instead, which represents the default byte order for network communications as per the IETF RFC; this is the same as > big-endian order, but codified to avoid confusion.
Without an explicit byte order marker, @, or native byte order, is assumed. In your specific case, your machine native byte order is little-endian, but that is a property of the specific machine architecture of your computer, not of Python.
1 Comment
The formats 'i' and 'I' are using your machine's native byte order, which in this case is little-endian. You can be explicit about what endianness you want to use.
>>> struct.unpack('i', b'\x00\x00\x00\x90') # native, implicit
(-1879048192,)
>>> struct.unpack('@i', b'\x00\x00\x00\x90') # native, explicit
(-1879048192,)
>>> struct.unpack('<i', b'\x00\x00\x00\x90') # explicitly little-endian
(-1879048192,)
>>> struct.unpack('>i', b'\x00\x00\x00\x90') # explicitly big-endian
(144,)
>>> struct.unpack('!i', b'\x00\x00\x00\x90') # explicitly network order
(144,)
Network protocols use big-endian as a machine-independent ordering.
Comments
Explore related questions
See similar questions with these tags.