1

In C, its quite common to have void functions take as argument its output parameters. I need to do this using a ctypes callback, so that I can update the pointer to the output from python.

The C code:

typedef void(*f1)(double*, double*);

void function_that_takes_a_function(f1 fn, double *input, double *output) {
    printf("I'm a function that takes a function\n");
    printf("input: %f\n", *input);
    printf("output before callback %f\n", *output);
    (*fn)(input, output);
    printf("output after callback: %f\n", *output);
}

And then to use this from C you would do:

void func_to_pass_in(double *x, double* y) {
    printf("hello from func_to_pass_in\n");
    printf("x is %f\n", *x);
    printf("y is %f\n", *y);
    *y = 2* (*x);
}

int main() {

    double input = 4.0;
    double output = 0.0;
    function_that_takes_a_function(func_to_pass_in, &input, &output);
    printf("Output is still : %f\n", output);
}

which outputs:

I'm a function that takes a function
input: 4.000000
output before callback 0.000000
hello from func_to_pass_in
x is 4.000000
y is 0.000000
output after callback: 8.000000
Output is still : 8.000000

In Python however, this is as far as I've got:

        import ctypes as ct

        lib = ct.CDLL("SRES")

        F1_FUNCTION_PTR = ct.CFUNCTYPE(None, ct.POINTER(ct.c_double), ct.POINTER(ct.c_double))

        lib.function_that_takes_a_function.argtypes = [
            F1_FUNCTION_PTR, ct.POINTER(ct.c_double), ct.POINTER(ct.c_double)
        ]
        lib.function_that_takes_a_function.restype = None

        def func_to_pass_in(x, y):
            print("hello from Python: ")
            print("x, y: ", x.contents, y.contents)
            y.contents = x.contents # <-- problem line

        # function_that_takes_a_function(func_to_pass_in, sres._makeDoubleArrayPtr([0.1, 0.1]))
        input = ct.c_double(4.0)
        output = ct.c_double(0.0)
        input_ptr = ct.pointer(input)
        output_ptr = ct.pointer(output)
        lib.function_that_takes_a_function(F1_FUNCTION_PTR(func_to_pass_in), input_ptr, output_ptr)

This will currently output:

I'm a function that takes a function
input: 4.000000
output before callback 0.000000
hello from Python: 
x, y:  c_double(4.0) c_double(0.0)
output after callback: 0.000000

Where it should actually output

I'm a function that takes a function changed
input: 4.000000
output before callback 0.000000
hello from Python: 
x, y:  c_double(4.0) c_double(0.0)
output after callback: 4.000000    <-- this line changed, we've updated the C variable from Python

I've tried a number of different strategies now, including using ctypes.memmove , a suggestion from here and ctypes.cast, a suggestion from here.

Any idea what I'm doing wrong?

Edit

I've also tried: ct.memmove(ct.cast(x, ct.c_void_p).value, ct.cast(y, ct.c_void_p).value, ct.sizeof(ct.c_double)) as "the problem line"

from here

1 Answer 1

3

This Python callback:

def func_to_pass_in(pin, pout):
    pout.contents = pin.contents

Is equivalent to this C code:

void callback(double* pin, double* pout) {
    pout = pin;  // re-assign local variable by value.  No effect on return.
}

What you want is to modify the value of the object y is currently pointing at, equivalent to this in C:

void callback(double* pin, double* pout) {
    *pout = *pin;  // dereference and change output content
}

Use the following to change the value in the Python callback:

def func_to_pass_in(pin, pout):
    pout.contents.value = pin.contents.value
Sign up to request clarification or add additional context in comments.

1 Comment

The solution I found was using to use ctypes.memmove. It worked but this is the better solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.