lively
lively

Reputation: 278

Issue returning values from C function called from Python

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?

Upvotes: 9

Views: 8913

Answers (1)

Adam Rosenfield
Adam Rosenfield

Reputation: 400146

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.

Upvotes: 16

Related Questions