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