Amit Davidi
Amit Davidi

Reputation: 223

Getting the wrong type when using a function imported from C in Python - Ctypes

I wanted to use a function written in C which maps a number from one range to another:

//mapping a number <value> from 0 -> <max>  to 
//<wanted_min> -> <wanted_max>

float map3(float value, float max, float wanted_min, float wanted_max) {
    return (( (value/max) * (wanted_max - wanted_min) ) + wanted_min);
}

which outputs the wanted result (-0.8 in this case) when I run it in C (in Visual Studio).

but when I run it in python (with the module ctypes):

from ctypes import *
c_funcs = CDLL("./myf.so")

def map_num(value, Max, wanted_min, wanted_max):

    x = c_funcs.map3(ctypes.c_float(value), ctypes.c_float(Max),
                     ctypes.c_float(wanted_min), ctypes.c_float(wanted_max))
    print(type(x))
    return x

print(map_num(10,  100, -1, 1))

output:

<class 'int'>
4 

the type of x is int, and I can't figure out why.

and if I use regular python I get the wanted result (of course):

def map_num(value, Max, wanted_min, wanted_max):
    return (((value  / Max ) * (wanted_max - wanted_min)) + wanted_min)

print(map_num(10,  100, -1, 1))

I get the wanted result which is -0.8 (for example in this case)

I'm sorry for the lack of PEP8, any help would be greatly appreciated !

Upvotes: 1

Views: 280

Answers (2)

tdelaney
tdelaney

Reputation: 77407

If you don't apply a prototype to function, ctypes assumes that arguments and return are int. See Specifying the required argument types (function prototypes). You can prototype your function so that nothing needs to be recast.

from ctypes import *
c_funcs = CDLL("./myf.so")

c_funcs.map3.argtypes = [c_float, c_float, c_float, c_float]
c_funcs.map3.restype = c_float

def map_num(value, Max, wanted_min, wanted_max):

    x = c_funcs.map3(value, Max, wanted_min, wanted_max)
    print(type(x))
    return x

print(map_num(10,  100, -1, 1))

Now that map3 has been fully prototyped, there isn't a need for the intermediate map_num function if all it does is call the C function and return its result.

Upvotes: 3

ti7
ti7

Reputation: 18876

ctypes can't infer the return type here and assumes it to be int, so you need to set it explicitly

Just do this before you call the function

    ...
    c_funcs.map3.restype = c_float
    c_funcs.map3(...)

From the docs https://docs.python.org/3/library/ctypes.html#return-types

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.

Upvotes: 1

Related Questions