Home > Blockchain >  How do you pass an array by reference from python to a C function using CTypes?
How do you pass an array by reference from python to a C function using CTypes?

Time:04-05

As the title says I have been trying for the last 48 hours to pass vectors from a python project to a set of C functions I have written. Eventually I came to the conclusion it might be easier using arrays instead of vectors based on some reading around of past posts on here. This led to me trying this tutorial below BUT it was originally only for exemplifying passing in an integer and returning it too. I tried changing the code so it would pass by reference a 3 number long list/array from python, and then add 1 to each of the numbers in it. However, when I run this, I can see it is getting the array no problem and printing the values modified in the c function, but it's not modifying the original python variable. In fact what I get "<class 'main.c_double_Array_3'>" back when I try to print output of the wrapper function. Below is the code I've tried so far (in its current state). If anyone could provide some direction regarding a resource for a good clear tutorial on how to do this, OR some help regarding what to do I would greatly appreciate it.

Simple_calculations C file

extern "C" void our_function(double * numbers) {
    numbers[0]  = 1;
    numbers[1]  = 1;
    numbers[2]  = 1;
    std::cout << numbers[0] << std::endl;
    std::cout << numbers[1] << std::endl;
    std::cout << numbers[2] << std::endl;
}

Python file

import os

import ctypes

# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    os.system('g   -dynamiclib -shared -o simple_calculations.dylib simple_calculations.cpp -std=c  17')

    _sum = ctypes.CDLL('simple_calculations.dylib')
    _sum.our_function.argtypes = (ctypes.POINTER(ctypes.c_double),)

    def our_function(numbers):
        array_type = ctypes.c_double * 3
        _sum.our_function(array_type(*numbers))
        return array_type

    z = our_function([0, 1, 2])

    print(z)

Output

1
2
3
<class '__main__.c_double_Array_3'>

CodePudding user response:

You are returning array_type. That’s a type, not an instance of the type. The instance is your array_type(*numbers) passed to the function, but it is not preserved. Assign it to a variable and return that, or better yet convert it back to a Python list as shown below:

test.cpp

#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

extern "C" API void our_function(double * numbers) {
    numbers[0]  = 1;
    numbers[1]  = 1;
    numbers[2]  = 1;
}

test.py

import ctypes

_sum = ctypes.CDLL('./test')
_sum.our_function.argtypes = ctypes.POINTER(ctypes.c_double),

def our_function(numbers):
    array_type = ctypes.c_double * 3  # equiv. to C double[3] type
    arr = array_type(*numbers)        # equiv. to double arr[3] = {...} instance
    _sum.our_function(arr)  # pointer to array passed to function and modified
    return list(arr)        # extract Python floats from ctypes-wrapped array

z = our_function([0, 1, 2])
print(z)

Output:

[1.0, 2.0, 3.0]
  • Related