Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a C function in Python

I've tried all the solutions mentioned on the internet so far nothing worked for me.

I have a python code, to speed it up, I want that my code runs the heavy calculations in a C function. I already wrote this C function.

Then, to share the library, I did this in the terminal :

gcc -shared -Wl,-install_name,testlib.so -o testlib.so -fPIC myModule.c

which returns no error. The problem; comes when i try to launch the C function in python. Let's consider the following simple function in C :

int multiplier(int a, int b)
{

int lol = 0;

lol = a*b;

return lol;
}

I launch python3 (3.5.2), and then :

import ctypes
zelib = ctypes.CDLL("/Users/longeard/Desktop/Codes/DraII/testlib.so",ctypes.RTLD_GLOBAL)

The library should be ready to use in python by doing :

res = zelib.multiplier(2,3)

When doing that, it works and python returns

6

Problem is, that the function i want to use ( the multiplier function I use is just for the example ) is supposed to take floats as input and return a float. But if I now consider the same multiplier function as before but with float :

float multiplier(float a, float b)
{

float lol = 0.0;

lol = a*b;

return lol;
}

I recompile using gcc, I reimport ctypes and re-do ctypes.CDLL, and I do in python3 :

zelib.multiplier(ctypes.c_float(2),ctypes.c_float(3))

(the types.c_float are here to convert the 2 in python into a float in C ), python will return :

2

This is weird because if I add a printf within the function to print lol, python will print :

  6.0

but still return 2, or 18 sometimes. Even though I printf and return the same variable "lol".

I tried a lot of things, and none of it worked. Do somebody have a idea please ? Thank You.

like image 579
Nicano Avatar asked Oct 18 '16 07:10

Nicano


2 Answers

You need to specify restype, argtypes of the function:

zelib = ctypes.CDLL('...')
zelib.multiplier.restype = ctypes.c_float   # return type
zelib.multiplier.argtypes = [ctypes.c_float, ctypes.c_float]  # argument types

According to Specifying the required argument types (function prototypes):

It is possible to specify the required argument types of functions exported from DLLs by setting the argtypes attribute.

and Return types in ctypes module documentation:

By default functions are assumed to return the C int type. Other return types can be specified by setting the restype attribute of the function object.


# without specifying types
>>> import ctypes
>>> zelib = ctypes.CDLL('testlib.so')
>>> zelib.multiplier(2, 3)
0

# specifying types
>>> zelib.multiplier.restype = ctypes.c_float
>>> zelib.multiplier.argtypes = [ctypes.c_float, ctypes.c_float]
>>> zelib.multiplier(2, 3)
6.0
like image 143
falsetru Avatar answered Nov 15 '22 04:11

falsetru


While @falsetru's answer is the better way of doing it an alternative is to simply write your C function to use doubles.

Floats are automatically promoted to double when calling a function without a parameter list.

like image 26
Lelanthran Avatar answered Nov 15 '22 03:11

Lelanthran