0

I want to pack a 10-bit integer and a 54-bit integer into a 64-bit structure. But this code ends up using 128 bits.

from ctypes import *

class ABC(Structure):
    _fields_ = [("a", c_int, 10), ("b", c_uint64, 54)]

print(sizeof(ABC) * 8) # 128
mcu
  • 3,302
  • 8
  • 38
  • 64

2 Answers2

2

For whatever reason, ctypes doesn't do bit packing properly when you mix different width objects into the same byte. Something like this appears to work for me:

class ABC(Structure):
   _pack_ = 1
   _fields_ = [("a",c_int64,10),("b",c_uint64,54)]
Mostly Harmless
  • 887
  • 1
  • 9
  • 9
  • What exactly does the `_pack_` attribute do and what are valid values for it? – mcu Oct 04 '15 at 19:00
  • http://stackoverflow.com/questions/14771150/python-ctypes-pragma-pack-for-byte-aligned-read - in essence it emulates C's `pragma pack`, but since your structure is byte aligned to a standard width already it probably affects nothing here – Mostly Harmless Oct 04 '15 at 19:05
  • As for valid values, https://docs.python.org/2/library/ctypes.html#ctypes.Structure._pack_ and other comments while searching around indicate that it'll take small positive powers of 2 – Mostly Harmless Oct 04 '15 at 19:06
  • I think this would apply to Python. https://msdn.microsoft.com/en-us/library/2e70t5y1.aspx *Specifies the value, in bytes, to be used for packing. ... Valid values are 1, 2, 4, 8, and 16. The alignment of a member will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.* – mcu Oct 04 '15 at 19:10
0

Considering int_10 and int_54 are integers with desired bitness:

>>> def pack(int_10, int_54):
...     return (int_10 & 0x3FF) | (int_54 & 0x3FFFFFFFFFFFFF) << 10

>>> bin(pack(1, 1))
'0b10000000001'
>>> bin(pack(1, 2 ** 54 - 1))
'0b1111111111111111111111111111111111111111111111111111110000000001'
>>> bin(pack(2 ** 10, 2 ** 54))
'0b0'

You can then pack the resulting integer using struct.pack to get a byte string.

>>> import struct
>>> struct.pack('Q', pack(2 ** 10 - 1, 2 ** 54 - 1))
'\xff\xff\xff\xff\xff\xff\xff\xff'
Maciej Gol
  • 15,394
  • 4
  • 33
  • 51
  • This is ok for compacting data for storage and such. But it won't let me manipulate the bit fields easily, like: `x=ABC(10,20);x.a=-15;x.b=50` I am really looking for Python's built-in functionality, if it exists. – mcu Oct 04 '15 at 17:53