简体   繁体   中英

python pack/unpack numbers specifyig number of bytes

I'm trying to convert int numbers (>=0 && <2^32 of course) in Python into a 4 byte unsigned int representation and back.

As I understand the docs the sizes given in struct.pack are a standard but the size is not guaranteed.. how can I make sure that I get 4 exactly bytes?

One way I found using ctypes:

byte_repr=bytes(ctypes.c_uint32(data))

Is this the most pythonic one there is? And what would be the way back (for this or any other solution)?

The types int and bytes have the methods you need for that.

Note that I am calling from_bytes from the class int but it can be called from an int instance object:

>>> a = 2**32-1
>>> a.to_bytes(4, 'little')
b'\xff\xff\xff\xff'
>>> b = a.to_bytes(4, 'little')
>>> c = int.from_bytes(b, 'little')
>>> c
4294967295
>>> a
4294967295
>>>

Given the mentioned interval, you're talking about unsigned int s .
[Python 3.Docs]: struct - Interpret strings as packed binary data works fine (well, on platforms (compilers) where sizeof(int) == 4 ).
Since for a vast majority of environments the above is true, you can safely use it (unless you're positive that the code will run on an exotic platform, where the compiler used to build Python is different).

 >>> import struct >>> >>> bo = "<" # byte order: little endian >>> >>> ui_max = 0xFFFFFFFF >>> >>> ui_max 4294967295 >>> buf = struct.pack(bo + "I", ui_max) >>> buf, len(buf) (b'\xff\xff\xff\xff', 4) >>> >>> ui0 = struct.unpack(bo + "I", buf)[0] >>> ui0 4294967295 >>> >>> i0 = struct.unpack(bo + "i", buf)[0] # signed int >>> i0 -1 >>> struct.pack(bo + "I", 0) b'\x00\x00\x00\x00' >>> >>> struct.pack(bo + "I", ui_max + 1) Traceback (most recent call last): File "<stdin>", line 1, in <module> struct.error: argument out of range >>> >>> struct.unpack(bo + "I", b"1234") (875770417,) >>> >>> struct.unpack(bo + "I", b"123") # 3 bytes buffer Traceback (most recent call last): File "<stdin>", line 1, in <module> struct.error: unpack requires a buffer of 4 bytes >>> >>> struct.unpack(bo + "I", b"12345") # 5 bytes buffer Traceback (most recent call last): File "<stdin>", line 1, in <module> struct.error: unpack requires a buffer of 4 bytes

Related (remotely): [SO]: Maximum and minimum value of C types integers from Python .

[Python 3.Docs]: ctypes - A foreign function library for Python variant:

 >>> # Continuation of previous snippet >>> import ctypes as ct >>> >>> ct_ui_max = ct.c_uint32(ui_max) >>> >>> ct_ui_max c_ulong(4294967295) >>> >>> buf = bytes(ct_ui_max) >>> buf, len(buf) (b'\xff\xff\xff\xff', 4) >>> >>> ct.c_uint32(ui_max + 1) c_ulong(0) >>> >>> ct.c_uint32.from_buffer_copy(buf) c_ulong(4294967295) >>> ct.c_uint32.from_buffer_copy(buf + b"\x00") c_ulong(4294967295) >>> ct.c_uint32.from_buffer_copy(b"\x00" + buf) # 0xFFFFFF00 (little endian) c_ulong(4294967040) >>> >>> ct.c_uint32.from_buffer_copy(buf[:-1]) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: Buffer size too small (3 instead of at least 4 bytes)

Note : @progmatico's answer is simpler and more straightforward as it doesn't involve any module other than builtin ( [Python 3.Docs]: Built-in Types - Additional Methods on Integer Types ). As a side note, sys.byteorder could be used.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM