Search code examples
pythonc++cctypeswrapper

float pointer in ctypes python and pass structure pointer


I'm trying to pass a structure pointer to the API wrapper, Where the struct is containing float pointer member. I'm not sure that how we can pass float pointer value to the structure.

/Structure/

class input_struct (ctypes.Structure):
    _fields_ = [
        ('number1', ctypes.POINTER(ctypes.c_float)),
        ('number2', ctypes.c_float),
        #('option_enum', ctypes.POINTER(option))
    ]

/wrapper/

init_func = c_instance.expose_init
init_func.argtypes = [ctypes.POINTER(input_struct)]

#help(c_instance)
inp_str_ptr = input_struct()
#inp_str_ptr.number1 = cast(20, ctypes.POINTER(ctypes.c_float)) # want to pass pointer
inp_str_ptr.number1 = 20 # want to pass as float pointer
inp_str_ptr.number2 = 100

c_instance.expose_init(ctypes.byref(inp_str_ptr))
c_instance.expose_operation()

Solution

  • You can either create a c_float instance and initialize with a pointer to that instance, or create a c_float array and pass it, which in ctypes imitates a decay to a pointer to its first element.

    Note that ctypes.pointer() creates pointers to existing instances of ctypes objects while ctypes.POINTER() creates pointer types.

    test.c - for testing

    #ifdef _WIN32
    #   define API __declspec(dllexport)
    #else
    #   define API
    #endif
    
    typedef struct Input {
        float* number1;
        float  number2;
    } Input;
    
    API void expose_init(Input* input) {
        printf("%f %f\n",*input->number1, input->number2);
    }
    

    test.py

    import ctypes
    
    class input_struct (ctypes.Structure):
        _fields_ = (('number1', ctypes.POINTER(ctypes.c_float)),
                    ('number2', ctypes.c_float))
    
    c_instance = ctypes.CDLL('./test')
    init_func = c_instance.expose_init
    # Good habit to fully define arguments and return type
    init_func.argtypes = ctypes.POINTER(input_struct),
    init_func.restype = None
    
    inp_str_ptr = input_struct()
    num = ctypes.c_float(20)     # instance of c_float, similar to C "float num = 20;"
    inp_str_ptr.number1 = ctypes.pointer(num) # similar to C "inp_str_ptr.number1 = #"
    inp_str_ptr.number2 = 100
    
    c_instance.expose_init(ctypes.byref(inp_str_ptr))
    
    # similar to C "float arr[1] = {30}; inp_str_ptr = arr;"
    inp_str_ptr.number1 = (ctypes.c_float * 1)(30)
    c_instance.expose_init(ctypes.byref(inp_str_ptr))
    

    Output:

    20.000000 100.000000
    30.000000 100.000000