Python 取消引用指向numpy数组或列表的无效指针

Python 取消引用指向numpy数组或列表的无效指针,python,numpy,ctypes,Python,Numpy,Ctypes,我通过ctypes从外部函数收到一个空指针,其中包含一个c\u double数组: [[12.0,13.0],[14.0,15.0],…] 我通过restype参数访问它: from ctypes import Structure, POINTER, c_void_p, c_size_t, c_double, c_uint32, c_char_p, cast, cdll class _CoordResult(Structure): """ Container for returned

我通过
ctypes
从外部函数收到一个空指针,其中包含一个
c\u double
数组:
[[12.0,13.0],[14.0,15.0],…]

我通过
restype
参数访问它:

from ctypes import Structure, POINTER, c_void_p, c_size_t, c_double, c_uint32, c_char_p, cast, cdll


class _CoordResult(Structure):
    """ Container for returned FFI coordinate data """
    _fields_ = [("coords", _FFIArray)]

class _FFIArray(Structure):
    """
    Convert sequence of float lists to a C-compatible void array
    example: [[1.0, 2.0], [3.0, 4.0]]

    """
    _fields_ = [("data", c_void_p),
                ("len", c_size_t)]

def _void_array_to_nested_list(res, _func, _args):
    """ Dereference the FFI result to a list of coordinates """
    shape = (res.coords.len, 2)
    array_size = np.prod(shape)
    mem_size = 8 * array_size
    array_str = string_at(res.coords.data, mem_size)
    array = [list(pair) for pair in ((POINTER(c_double * 2).from_buffer_copy(res.coords)[:res.coords.len]))]
    drop_array(res.coords)
    return array

decode_polyline = lib.decode_polyline_ffi
decode_polyline.argtypes = (c_char_p, c_uint32)
decode_polyline.restype = _CoordResult
decode_polyline.errcheck = _void_array_to_nested_list
但是,这会返回无意义的值,因为
\u void\u array\u到\u nested\u list
中的指针解引用是错误的


解决方案不必使用NumPy,但这似乎是最好的方法。

我现在无法测试,但我会尝试以下方法:

import numpy as np

result = ...
shape = (10, 2)
array_size = np.prod(shape)
mem_size = 8 * array_size
array_str = ctypes.string_at(result, mem_size)
array = np.frombuffer(array_str, float, array_size).reshape(shape)

array
将是只读的,如果您需要一个可写的数组,请复制它。

这里有一个解决方案,它使用
ctypes.cast
numpy.ctypeslib.as_数组
,并且在
处不使用
ctypes.string_,以防它额外复制内存区域

class _FFIArray(Structure):
    _fields_ = [("data", c_void_p), ("len", c_size_t)]

class Coordinate(Structure):
    _fields_ = [("latitude", c_double), ("longitude", c_double)]

class Coordinates(Structure):
    _fields_ = [("data", POINTER(Coordinate)), ("len", c_size_t)]

decode_polyline = lib.decode_polyline_ffi
decode_polyline.argtypes = (c_char_p, c_uint32)
decode_polyline.restype = _FFIArray

# assuming that the second argument is the length of polyline, 
# although it should not be needed for `\0` terminated string
res = decode_polyline(polyline, len(polyline))

nres = Coordinates(cast(res.data, POINTER(Coordinate)), res.len)
for i in range(nres.len):
    print(nres.data[i].latitude, nres.data[i].longitude)

# if just a numpy (np) array is needed
xs = np.ctypeslib.as_array((c_double * res.len * 2).from_address(res.data))
# "New view of array with the same data."
xs = xs.view(dtype=[('a', np.float64), ('b', np.float64)], type=np.ndarray)
xs.shape = res.len 

A将是有用的。您是否验证了被调用的函数首先返回了合理的值,即在没有ctypes的情况下测试代码?@J.J.Hakala Done!是的,当在没有ctypes的情况下进行测试时,该函数返回合理的值。是否有任何原因导致此操作在Windows上失败?使用
dtype=“float64”
,它在*nix和OSX上可以完美工作,但在32位和64位窗口上,大约有50%的时间返回无意义的值。如果没有更多信息,很难进行调试,但这听起来可能与Windows的长期问题有关。检查指针,确保使用适合平台的指针类型。