Search code examples
pythonnumpystructpackunpack

How can I use the struct library in python to pack a double into two uint32's


So this is what I would like to do: I have a double and I need to pack it into binary data and then get the upper four bytes and store them into a uint32 (it has to do with a device driver).

I already do this with floats:

import struct
import numpy as np
tmp = struct.pack('<f',float(datatobeconverted))
dataout = np.uint32(struct.unpack('<I',tmp))

I would like to do this with doubles but It doesn't seem to work:

tmp = struct.pack('<d',double(datatobeconverted))
dataout0 = np.uint32(struct.unpack('<I',tmp[0:3]))
dataout1 = np.uint32(struct.unpack('<I',tmp[4:7]))

Any ideas? By the way, I think the way struct stores binary data is unintuitive and hard to read


Solution

  • You're just slicing tmp wrong.

    >>> dataout0 = np.uint32(struct.unpack('<I',tmp[0:3]))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    struct.error: unpack requires a string argument of length 4
    >>> 
    

    The error message is pretty clear: the string arg you're passing is not "of length 4".

    Python slices are always "right-bound excluded". So, to slice off the first 4 bytes, you do:

    >>> dataout0 = np.uint32(struct.unpack('<I',tmp[:4]))
    

    The 0: in 0:4 is optional, and it's best to avoid it, as a matter of style, to minimize clutter (Tufte's "no wasted pixels" principle).

    Similarly, to get everything but the first four bytes,

    >>> dataout1 = np.uint32(struct.unpack('<I',tmp[4:]))
    

    Left-bound is included, so you can use the same value (here, 4) for both slicings (one of the advantage of the right-bound-excluded concept, helping you avoid off-by-one errors).

    I first met this principle decades ago in Koenig's still-awesome book "C traps and pitfalls" and I have lived by it since -- and the principle's consistent adoption is part of what me love Python at first sight:-).

    (I believe some kind of slicing on pandas frames is the one exception to this principle throughout widespread Python libraries -- and part of why I can't get whole-heartedly into pandas... but, that's another story!-).