1

I need to split a 16-bit unsigned integer into an array of bytes (i.e. array.array('B')) in python.

For example:

>>> reg_val = 0xABCD
[insert python magic here]
>>> print("0x%X" % myarray[0])
0xCD
>>> print("0x%X" % myarray[1])
0xAB

The way I'm currently doing it seems very complicated for something so simple:

>>> import struct
>>> import array
>>> reg_val = 0xABCD
>>> reg_val_msb, reg_val_lsb = struct.unpack("<BB", struct.pack("<H", (0xFFFF & reg_val)))
>>> myarray = array.array('B')
>>> myarray.append(reg_val_msb)
>>> myarray.append(reg_val_lsb)

Is there a better/more efficient/more pythonic way of accomplishing the same thing?

cdwilson
  • 4,310
  • 4
  • 26
  • 32

3 Answers3

1

(using python 3 here, there are some nomenclature differences in 2)

Well first, you could just leave everything as bytes. This is perfectly valid:

reg_val_msb, reg_val_lsb = struct.pack('<H', 0xABCD)

bytes allows for "tuple unpacking" (not related to struct.unpack, tuple unpacking is used all over python). And bytes is an array of bytes, which can be accessed via index as you wanted.

b = struct.pack('<H',0xABCD)

b[0],b[1]
Out[52]: (205, 171)

If you truly wanted to get it into an array.array('B'), it's still rather easy:

ary = array('B',struct.pack('<H',0xABCD))
# ary = array('B', [205, 171])

print("0x%X" % ary[0])
# 0xCD
roippi
  • 25,533
  • 4
  • 48
  • 73
  • can you elaborate on "tuple unpacking" vs. `struct.unpack`? i.e. is there a difference between `b[0],b[1]` and `struct.unpack(' – cdwilson Apr 28 '14 at 23:15
  • Not really. Tuple unpacking is just assigning each element of an iterable length *n* to *n* different variables. Like `a,b,c = 1,2,3`. – roippi Apr 29 '14 at 01:03
0

For non-complex numbers you can use divmod(a, b), which returns a tuple of the quotient and remainder of arguments.

The following example uses map() for demonstration purposes. In both examples we're simply telling divmod to return a tuple (a/b, a%b), where a=0xABCD and b=256.

>>> map(hex, divmod(0xABCD, 1<<8)) # Add a list() call here if your working with python 3.x
['0xab', '0xcd']

# Or if the bit shift notation is distrubing:
>>> map(hex, divmod(0xABCD, 256))

Or you can just place them in the array:

>>> arr = array.array('B')
>>> arr.extend(divmod(0xABCD, 256))
>>> arr
array('B', [171, 205])
msvalkon
  • 11,887
  • 2
  • 42
  • 38
  • Thanks for the answer. I chose the answer from @roippi because it's more generally applicable (for example can be extended to split 24-bit integers into bytes) – cdwilson Apr 28 '14 at 23:08
  • That's fine but I would like to mention that the `divmod()` can be extended to any bit range by passing a correct parameter to it. For 24 bits: `divmod(0xABCD,0xFFFFFF)`. – msvalkon Apr 29 '14 at 05:30
  • how would you split 0x123456 into bytes 0x12, 0x34, 0x56 using divmod? – cdwilson Apr 30 '14 at 16:02
  • @cdwilson sorry I misunderstood your original comment. Of course this doesn't work with divmod without doing two calls. – msvalkon May 01 '14 at 21:28
0

You can write your own function like this.

def binarray(i):
    while i:
        yield i & 0xff
        i = i >> 8

print list(binarray(0xABCD))
#[205, 171]
Kei Minagawa
  • 4,395
  • 3
  • 25
  • 43