How to pack and unpack using ctypes (Structure <-> str)

Posted on

Question :

How to pack and unpack using ctypes (Structure <-> str)

This might be a silly question but I couldn’t find a good answer in the docs or anywhere.

If I use struct to define a binary structure, the struct has 2 symmetrical methods for serialization and deserialization (pack and unpack) but it seems ctypes doesn’t have a straightforward way to do this. Here’s my solution, which feels wrong:

from ctypes import *

class Example(Structure):
    _fields_ = [
        ("index", c_int),
        ("counter", c_int),

def Pack(ctype_instance):
    buf = string_at(byref(ctype_instance), sizeof(ctype_instance))
    return buf

def Unpack(ctype, buf):
    cstring = create_string_buffer(buf)
    ctype_instance = cast(pointer(cstring), POINTER(ctype)).contents
    return ctype_instance

if __name__ == "__main__":
    e = Example(12, 13)
    buf = Pack(e)
    e2 = Unpack(Example, buf)
    assert(e.index == e2.index)
    assert(e.counter == e2.counter)
    # note: for some reason e == e2 is False...
Asked By: Mr Temp


Answer #1:

The PythonInfo wiki has a solution for this.

FAQ: How do I copy bytes to Python from a ctypes.Structure?

def send(self):
    return buffer(self)[:]

FAQ: How do I copy bytes to a ctypes.Structure from Python?

def receiveSome(self, bytes):
    fit = min(len(bytes), ctypes.sizeof(self))
    ctypes.memmove(ctypes.addressof(self), bytes, fit)

Their send is the (more-or-less) equivalent of pack, and receiveSome is sort of a pack_into. If you have a “safe” situation where you’re unpacking into a struct of the same type as the original, you can one-line it like memmove(addressof(y), buffer(x)[:], sizeof(y)) to copy x into y. Of course, you’ll probably have a variable as the second argument, rather than a literal packing of x.

Answered By: Mark Rushakoff

Answer #2:

Have a look at this link on binary i/o in python:

Based on this you can simply write the following to read from a buffer (not just files):

g = open("foo","rb")
q = Example()

To write is simply:


The same for using sockets:




I did some testing with pack/unpack and ctypes and this approach is the fastest except for writing straight in C

Answered By: Ralph Paul

Answer #3:

Tested on Python3

e = Example(12, 13)
serialized = bytes(e)
deserialized = Example.from_buffer_copy(serialized)
Answered By: TomDotTom

Leave a Reply

Your email address will not be published. Required fields are marked *