Eryk Sun <eryk...@gmail.com> added the comment:

Your example uses POINTER(c_double), not c_void_p. There's no problem with an 
actual pointer object (i.e. subclass of ctypes._Pointer). The problem is with 
simple types (i.e. immediate subclasses of ctypes._SimpleCData), including 
simple pointer types (i.e. c_void_p, c_char_p, c_wchar_p). Simple types are 
automatically converted to equivalent Python types when returned from functions 
or accessed in aggregates (i.e. structs and arrays). This is generally 
convenient, but at times it's a serious problem. 

Note that I said this is the case only for immediate subclasses of 
_SimpleCData. We can work around the behavior by using a subclass of the given 
simple type. For example:

    class my_wchar_p(ctypes.c_wchar_p): 
        pass

    class T(ctypes.Structure):
        _fields_ = (('s1', ctypes.c_wchar_p), 
                    ('s2', my_wchar_p))

    >>> t = T('abc', 'def')
    >>> t.s1
    'abc'
    >>> t.s2
    my_wchar_p(140497806976112)
    >>> t.s2.value
    'def'

If desired, we can retain the automatic conversion for function results by 
defining a staticmethod or classmethod named "_check_retval_" on the subclass. 
This method takes the result as parameter to be checked, possibly converted, 
and returned.

One exception is that [wide-]character arrays always get converted into 
bytes/strings when accessed as fields of a struct. This is implemented in 
PyCField_FromDesc in Modules/_ctypes/cfield.c. We can't easily work around this 
hack because it doesn't check whether the base type is an immediate subclass of 
_SimpleCData. Instead we have to use the undocumented `offset` attribute. We 
can hide this workaround with a private field and a property. For example:

    class T(ctypes.Structure):
        _fields_ = (('s1', ctypes.c_wchar * 10),
                    ('_s2', ctypes.c_wchar * 10))
        @property
        def s2(self):
            offset = type(self)._s2.offset
            return (ctypes.c_wchar * 10).from_buffer(self, offset)

    >>> t = T('abc', 'def')
    >>> t._s2
    'def'
    >>> t.s2
    <__main__.c_wchar_Array_10 object at 0x7fc82c3a6510>
    >>> t.s2.value
    'def'

----------
nosy: +eryksun

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue35390>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to