Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ctypes Return Array

I'm trying to have a python wrapper for an array sort function in C. The C takes the array, sorts the integers by smallest to largest, then returns the array. But when I run it however, I get error:

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

And the libsortarray function

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;
}
like image 803
cclloyd Avatar asked Apr 14 '26 17:04

cclloyd


1 Answers

If the source is C++, you need to declare the function as extern "C" int *sortArray(int, int *). Also, when a function returns a pointer, set the restype attribute to a pointer type, which in this case would be sortArray.restype = POINTER(c_int). Otherwise in a 64-bit process the address gets truncated to 32-bit, creating a bad pointer that will potentially segfault when accessed. Also, and this is more a matter of style, declaring global libsortarray and manually wrapping arraySize as c_int(arraySize) are both unnecessary clutter.

That said, the library function sorts the array in place, so there's no reason to return anything, i.e. just make the return type void. Here's an example that implements this suggested modification.

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)[:]

Output:

Unsorted Array:
[7, 0, 8, 4, 3, 6, 9, 1, 5, 2]
Sorted Array:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
like image 90
Eryk Sun Avatar answered Apr 17 '26 06:04

Eryk Sun