Ctypes返回数组

3

我正在尝试为C语言中的数组排序函数编写Python包装器。该C函数接收数组,按照从小到大的顺序对整数进行排序,然后返回排序后的数组。但是当我运行它时,出现了错误:

Traceback (most recent call last):
  File "sortarray.py", line 25, in <module>
    newarray = sortArray(array)
  File "sortarray.py", line 8, in sortArray
    libsortarray.sortArray.argtypes = (ctypes.c_int, ctypes.POINTER(ctypes.c_int))
  File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ctypes/__init__.py", line 378, in __getattr__
    func = self.__getitem__(name)
  File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ctypes/__init__.py", line 383, in __getitem__
    func = self._FuncPtr((name_or_ordinal, self))
AttributeError: dlsym(0x7f84484280e0, sortArray): symbol not found

Python:

import ctypes

libsortarray = ctypes.CDLL('libsortarray.so')

def sortArray(array):
    global libsortarray
    libsortarray.sortArray.argtypes = (ctypes.c_int, ctypes.POINTER(ctypes.c_int))
    arraySize = len(array)
    array_type = ctypes.c_int * arraySize
    result = libsortarray.sortArray(ctypes.c_int(arraySize), array_type(*array))
    return result


file = open('bigarray.txt', 'r')
#Bigarray.txt is just 10,000 lines each with a single integer
array = []
arraySize = 10000
for i in range(0,arraySize):
    array.append(int(file.readline()))
file.close()

newarray = sortArray(array)
print newarray

而 libsortarray 函数

int* sortArray(int, int*);

int* sortArray(int arraySize, int* array) {
    int temp, i, j;
    for (i=0; i<arraySize; i++)
        for (j=i+1; j<arraySize; j++)
            if (array[i] > array[j]) {
                temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
    return array;
}

可以了。不过我有个问题,当我使用 for i in newarray 时,它会返回一些随机整数和我认为是内存地址。如果我使用 for i in rangenewarray[i] 就可以正常工作,但是否有办法仍然使用这种返回类型的 for in 循环呢? - cclloyd
我之前确实有restype,但在这篇文章中删除了它,因为没有它会给我带来更少的错误。当我将C中的返回类型移除并改为void时,它就不再对数组进行排序了。如果没有返回类型,则在尝试打印数组时会出现错误。所以我正在解决这个问题。但是除此之外,我该如何将其转换回Python类型数组呢?当我对数组进行排序,然后执行另一个名为reverseArray(size, array)的函数时,它似乎会导致segfault(Python而非c代码)。在只需要大约500毫秒才能segfault时,它也需要一段时间。newarray=reverseArray(arraySize,newarray) - cclloyd
1个回答

5
如果源代码是C++,则需要将函数声明为extern "C" int *sortArray(int, int *)。此外,当函数返回指针时,将restype属性设置为指针类型,即在本例中为sortArray.restype = POINTER(c_int)。否则,在64位进程中,地址会被截断为32位,创建一个坏指针,可能导致访问时崩溃。另外,这更多是一种风格问题,声明global libsortarray并手动封装arraySizec_int(arraySize)都是不必要的冗余。
话虽如此,库函数会直接对数组进行排序,因此没有任何理由返回任何东西,即只需将返回类型设置为void。以下是实现此建议修改的示例。 sortarray.cpp:
extern "C" void sortArray(int, int *);

void sortArray(int arraySize, int *array)
{
    int temp, i, j;
    for (i = 0; i < arraySize; i++)
        for (j = i + 1; j < arraySize; j++)
            if (array[i] > array[j]) {
                temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
}

// g++ -shared -fPIC -o libsortarray.so sortarray.cpp

sortarray.py

import ctypes

libsortarray = ctypes.CDLL('./libsortarray.so')

libsortarray.sortArray.restype = None
libsortarray.sortArray.argtypes = (ctypes.c_int, 
                                   ctypes.POINTER(ctypes.c_int))

def sort_array(array):
    """Return a sorted copy of the input array or sequence."""
    array_size = len(array)
    array = (ctypes.c_int * array_size)(*array)
    libsortarray.sortArray(array_size, array)
    return array

if __name__ == '__main__':
    seq = [7, 0, 8, 4, 3, 6, 9, 1, 5, 2]
    print 'Unsorted Array:\n', seq
    print 'Sorted Array:\n', sort_array(seq)[:]

输出:

Unsorted Array:
[7, 0, 8, 4, 3, 6, 9, 1, 5, 2]
Sorted Array:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接