1

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
asked Feb 1, 2021 at 20:52
0

2 Answers 2

6

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.

answered Feb 1, 2021 at 20:55
Sign up to request clarification or add additional context in comments.

1 Comment

Damn. That's it! See I knew it was simple, I just couldn't see it.
2

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.

answered Feb 1, 2021 at 21:02

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.