On Mon, Oct 3, 2016 at 2:35 PM, Michael Felt <mich...@felt.demon.nl> wrote: > On 02-Oct-16 23:44, eryk sun wrote: >> On Sun, Oct 2, 2016 at 5:50 PM, Michael Felt <mich...@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 -- https://mail.python.org/mailman/listinfo/python-list