working with ctypes and complex data structures

eryk sun eryksun at gmail.com
Sun Oct 2 17:44:26 EDT 2016


 On Sun, Oct 2, 2016 at 5:50 PM, Michael Felt <michael at felt.demon.nl> wrote:
>
> a) where is documentation on "CField"'s?

It's undocumented. A CField is a data descriptor that accesses a
struct field with the given type, size, and offset. Like most
descriptors, it's meant to be accessed as an attribute of an instance,
not as an attribute of the type.

When accessed as an attribute of a struct type, the value returned is
the CField descriptor itself. One reason to reference the descriptor
is for its "offset" attribute, since there's no offsetof() in ctypes.
At least in this regard it should be documented.

> b) what I am not understanding - as the basic documentation shows FOO.value
> as the way to set/get the value of a _field_

You may be surprised when accessing simple-type fields such as c_int
and c_char_p. These simple types have getter and setter functions that
get called automatically whenever the type is used as a function
result, array index, or struct field. For example:

    class Foo(ctypes.Structure):
        _fields_ = (('v', ctypes.c_int),)

    >>> foo = Foo()
    >>> foo.v = 5
    >>> foo.v
    5

You can use a subclass to avoid the getfunc's automatic conversion. For example;

    class my_int(ctypes.c_int):
        pass

    class Bar(ctypes.Structure):
        _fields_ = (('v', my_int),)

    >>> bar = Bar()
    >>> bar.v = 5
    >>> bar.v
    <my_int object at 0x7f7385e8aae8>
    >>> bar.v.value
    5

> class time_t(Structure):
> ...
>     if (maxsize > 2**32):
>         _fields_ = [("v", c_long)]
>     else:
>         _fields_ = [("v", c_int)]

I'd alias the type instead of defining a struct, e.g. `time_t =
c_long`. This preserves automatic conversion of the simple type.

Also, sys.maxsize is based on the platform's size_t type. That's
generally the same size as a pointer, but C doesn't require this.
Instead use sizeof(c_void_p), which will be 8 on a 64-bit platform and
4 on a 32-bit platform.

Also, while it's unrelated to your current problem, bear in mind that
int and long are both always 32-bit on Windows. c_int64 is a
cross-platform 64-bit integer.



More information about the Python-list mailing list