[issue27274] [ctypes] Allow from_pointer creation

Eryk Sun report at bugs.python.org
Thu Jun 9 04:32:49 EDT 2016


Eryk Sun added the comment:

Probably adding from_pointer is a good idea. That said, there's a simpler way to go about getting a bytes copy for a pointer.

Say that you have a pointer p for the following array:

    >>> a = (c_float * 3)(1, 2, 3)
    >>> bytes(a)
    b'\x00\x00\x80?\x00\x00\x00@\x00\x00@@'
    >>> p = POINTER(c_float)(a)

IMO, the most straight-forward way to get a bytes copy is to call string_at:

    >>> string_at(p, sizeof(p.contents) * 3)
    b'\x00\x00\x80?\x00\x00\x00@\x00\x00@@

In 3.x string_at uses the FFI machinery to call the following function:

    static PyObject *
    string_at(const char *ptr, int size)
    {
        if (size == -1)
            return PyBytes_FromStringAndSize(ptr, strlen(ptr));
        return PyBytes_FromStringAndSize(ptr, size);
    }

The first argument can be any type accepted by c_void_p.from_param, such as a ctypes pointer/array, str, bytes, or an integer address.

Alternatively, note that pointer instantiation is the same as setting the `contents` value, which accepts any ctypes data object. Here's the C code that implements this assignment:

    dst = (CDataObject *)value;
    *(void **)self->b_ptr = dst->b_ptr;

The b_ptr field points at the buffer of the ctypes data object. Thus you can cast p to a char pointer without even calling the cast() function, which avoids an FFI call:

    >>> bp = POINTER(c_char)(p.contents)

Slicing c_char and c_wchar pointers is special cased to return bytes and str, respectively. So you can slice bp to get bytes:

    >>> bp[:sizeof(p.contents) * 3]
    b'\x00\x00\x80?\x00\x00\x00@\x00\x00@@'

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

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue27274>
_______________________________________


More information about the Python-bugs-list mailing list