C-Style Unions And Python

So, you’re creating a C Union (used to create a variant type) and writing it to a file, socket, etc and want to read that in Python. There are two ways to deal with this.

Assume the following union definition in C

typedef union {
    int i;
    unsigned int u;
    float f;
} data_t;

In C, reading the value represented by this is easy.  Since its 4 bytes, you simply read 4 bytes and then reference the appropriate element.  In Python, if your looking for functionality to closely match C, it seems not so straight forward.

struct.pack and struct.unpack

The first thing you try to do is look at the struct module and see if pack and unpack can come close to doing what you want.  The problem with pack and unpack is that it requires a data type.

from struct import unpack
# byte_buffer -> binary input
# var_type -> variable type indicator
unpack_code = ''
if var_type == 'INT':
    unpack_code = 'i'
elif var_type == 'UINT':
    unpack_code = 'I'
elif var_type == 'FLOAT'
    unpack_code = 'f'
var = unpack(unpack_code, byte_buffer)[0]

This works just as well as anything and is completely straightforward, the big problem here is speed.  First, we have to do an if around each call to unpack to get the appropriate option.  Second, its faster to pull in arrays in python than single values.

A ctypes addition to struct.pack and struct.unpack

Using ctypes, you can approach a functionality similar C.  Take the following code for example.

from ctypes import c_int, c_uint, c_float, Union
from struct import unpack
class MyType(Union):
    _fields_ = [("i", c_int), ("u", c_uint), ("f", c_float)]
var = MyType()
var.i = unpack("i", byte_buffer)[0]
# then var.i, var.u, var.f contain the integer, unsigned int, and float representations respectively.

Notice that it is always unpacking the data as an integer into the integer part of the union.  This approach has a few advantages.  One, it functions the same as the C version of the code would.  Two, you can unpack entire arrays at once which can be faster.

Conclusions

The first code sample seems to be the simplest and most straightforward though potentially slower.  However, depending on the situation, you may want an implementation similar to the second.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply