Wrong return value from c function wrapped in python

Viewed 119

That's bizarre, I'm trying to wrap a function I've written in c in order to use it in python, in order to understand how to do it I've made an example:

cfunctions.c:

double dotproduct(int dim, double a[dim], double b[dim]){
    double res = 0;
    for(int i = 0; i < dim; i++){
        res = res + a[i]*b[i];
    }
    return res;
}

py_cfunctions.py:

from ctypes import *
import numpy as np

# so_file genreated with:
# cc -fPIC -shared -o cfunctions.so cfunctions.c
so_file = 'MY_PATH/cfunctions.so'
py_cfunctions = CDLL(so_file)
c_double_p = POINTER(c_double)
# Preparing example

def dotproduct(n,a,b):
    # Convert np.array to ctype doubles
    a_data = a.astype(np.double)
    a_data_p = a_data.ctypes.data_as(c_double_p)
    b_data = b.astype(np.double)
    b_data_p = b_data.ctypes.data_as(c_double_p)
    # Compute result...
    c_return = py_cfunctions.dotproduct(n,a_data_p,b_data_p)
    if (c_return != -1):
        return c_return
    else:
        return "C Function failed, check inputs"
 
py_cfunctions.dotproduct.argtypes= [c_int, c_double_p, c_double_p] 

The funny thing is that the code seems to work but the returned value is always equal to n. If I try to print res before returning it I can see that the value is correct, however the actual returned value is always n. What am I missing?

>>> import py_cfunctions as pycf
>>> import numpy as np
>>> a = np.array([1,2,3,4])
>>> b = np.array([4,5,6,1])
>>> pycf.dotproduct(4,a,b)
4

1 Answers

Thanks to @Mark Tolonen for the answer:

"At the implementation level, integers are returned in different registers than floating point values. ctypes assumes c_int for return value unless told otherwise. When using ctypes 'explicit is better than implicit'. Always define .restype and .argtypes correctly and you'll have fewer issues."

I had to explicitly define the return type of my function adding the following line to pic_functions.py:

py_cfunctions.dotproduct.restype = c_double

Related