Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue returning values from C function called from Python

Tags:

python

ctypes

I'm have difficulty with a seeming simple problem. There are various C functions that I need to call from Python code. Currently, I'm trying to do this through ctypes. I'm having issues with a simple example implementation that I'm using to ensure that everything works as intended before changing large chunks of existing code. The C functions take a few parameters, do various mathematical calculations, and then return a double value. This is the C file that I'm using as a test.

#include "Python.h"

double eval(double* args, int length, double* rands, int randLength, int debug)
{
    double val1 = args[0];
    double val2 = rands[0];
    double ret = val1 + val2;
    return ret;
}

In my actual test function I'm printing val1 and val2 to ensure they're receiving values. Everything is fine on that end. The Python that calls this function is the following.

test = ctypes.CDLL("/home/mjjoyce/Dev/C2M2L/AquaticWavesModel.so")
rand = Random();

args = [2]
argsArr = (ctypes.c_double * len(args))()
argsArr[:] = args

argsRand = [rand.random()]
argsRandArr = (ctypes.c_double * len(argsRand))()
rgsRandArr[:] = argsRand

result = test.eval(argsArr, len(argsArr), argsRandArr, len(argsRandArr), 0)
print "result", result

When this prints the returned result, it usually dumps a large negative number. It's my assumption that I need to do some converting before Python can handle the value, but I can't find an answer for that for the life of me. I've searched forever, but I'm not certain if I'm missing the obvious, or searching for the wrong information.

Also, if I change the return type of the function to int, the calculations turn out correct and an int is returned and printed as expected. If I set it to double, the calculations are correct in the C code (I print them to check), but Python doesn't like the returned result.

Any ideas what I'm missing?

like image 818
lively Avatar asked Aug 03 '12 20:08

lively


People also ask

Can Python call C functions?

We can call a C function from Python program using the ctypes module.

Why is my function not returning a value in C?

In C there are no subroutines, only functions, but functions are not required to return a value. The correct way to indicate that a function does not return a value is to use the return type "void". ( This is a way of explicitly saying that the function returns nothing. )

How does Python call C code?

cPython has two main ways to call C code: either by loading a shared library and calling its symbols, or by packing C code as Python binary modules and then calling them from Python code as though they were ordinary Python modules, which is how high performance stuff in the standard library is implemented - e.g. json.


1 Answers

You should set the function's argument types and return type in Python using the argtypes and restype members:

test.eval.argtypes = [ctypes.POINTER(ctypes.c_double),
                      ctypes.c_int,
                      ctypes.POINTER(ctypes.c_double),
                      ctypes.c_int,
                      ctypes.c_int]
test.eval.restype = ctypes.c_double

Then you can call it like you're doing: construct arrays of type (ctypes.c_double * length) initialized with your values, and the result will be a double.

See also this ctypes tutorial, it has lots of useful info.

like image 58
Adam Rosenfield Avatar answered Oct 09 '22 21:10

Adam Rosenfield