working with ctypes and complex data structures

Michael Felt michael at felt.demon.nl
Wed Oct 5 17:11:49 EDT 2016


Never said thank you - so, thanks!

What I need to do was add the .v at the end so I was accessing the value 
of the structure.

Unlilke Linux, AIX - for reasons unknown to all, they have the time_t 
definition that is specific to the ABI size, at least for these 
performance libraries that probably originated before 64-bit was a 
concern. So my guess is that the dual size in the struct, depending on 
the application size (not the kernel) is to maintain compatibility with 
32-bit applications that had been built against/on a 32-bit kernel.

So, lucky for me it did not work intiallly - because it made me pause 
and understand better what I had written.

And now the real thankyou for the detail you shared!

M


On 03-Oct-16 17:53, eryk sun wrote:
> On Mon, Oct 3, 2016 at 2:35 PM, Michael Felt <michael at felt.demon.nl> wrote:
>> 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:
>>>
>>>> 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.
> No, c_ulonglong is a simple (fundamental) type, which behaves just
> like other simple types such as c_int or c_char_p.
>
> On platform's with a 64-bit long, c_ulonglong is an alias for c_ulong
> (i.e. type "L"). On the other hand, on 64-bit Windows, c_ulonglong is
> an unsigned quad word (i.e. type "Q").
>
> All simple types subclass ctypes._SimpleCData and define a `_type_`
> code such as "c" for c_char. On 64-bit Linux the simple types are
> defined as follows:
>
>      ?: c_bool
>      c: c_char
>      z: c_char_p
>      u: c_wchar
>      Z: c_wchar_p
>      P: c_void_p
>
>      b: c_int8, c_byte
>      B: c_uint8, c_ubyte
>      h: c_int16, c_short
>      H: c_uint16, c_ushort
>      i: c_int32, c_int
>      I: c_uint32, c_uint
>      l: c_int64, c_long, c_longlong, c_ssize_t
>      L: c_uint64, c_ulong, c_ulonglong, c_size_t
>
>      f: c_float
>      d: c_double
>      g: c_longdouble
>
> For convenience, simple types are automatically converted when
> accessed as a function result, struct field, or array index. As I
> mentioned previously, the only way around this behavior is to use a
> subclass. A subclass doesn't get automatically converted because it
> might define custom methods and attributes that need to be preserved.
>
>>> 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
> I don't follow. Currently you wrap a c_int or c_long in a struct when
> you could just use those types directly. You have to check the pointer
> size, but then it's up to you what assumptions to make about the
> target platform's integer sizes. Currently on a 64-bit system you're
> assuming a Unix-style LP64 data model [1], in which a long is 64-bit.
> That should be fine if you're writing Unix-specific code that doesn't
> care about LLP64 Windows systems.
>
> Wrapping the type in a struct provides more type safety, but if I
> wanted that I'd create my own simple subclass. For example, assuming
> time_t should be a signed integer that's the same size as a pointer:
>
>      class time_t(ctypes._SimpleCData):
>          if ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_longlong):
>              _type_ = ctypes.c_longlong._type_
>          elif ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_long):
>              _type_ = ctypes.c_long._type_
>          elif ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_int):
>              _type_ = ctypes.c_int._type_
>          # else raise AttributeError for missing _type_
>
> [1]: https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models




More information about the Python-list mailing list