working with ctypes and complex data structures
Michael Felt
michael at felt.demon.nl
Mon Oct 3 10:35:43 EDT 2016
On 02-Oct-16 23:44, eryk sun wrote:
> 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.
So I do not feel so bad about not finding anything :)
> 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:
OK - so lucky me - it "does not work" like earlier examples because I am
referencing, generally, c_ulonglong - and these do not have a automatic
getter/setter function? If not, how do I go about making one (preferably
without needing to right a "method" for each and every _field_ in a class.
> 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
I'll try it also with my c_int/c_uint fields - maybe these just work. If
so, again - how do I get a c_ulonglong?
>
>> 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.
The reason for the not using alias is because a) I was trying to be more
inline with the text of the include file.
I will have to check the sizeof c_long (i.e., sizeof(long) in both 32
and 64-bit modes
> 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.
Thanks!
>
> 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