Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
153 views
in Technique[技术] by (71.8m points)

How to update the value of a C output parameter from python using a ctypes callback?

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
");
    printf("input: %f
", *input);
    printf("output before callback %f
", *output);
    (*fn)(input, output);
    printf("output after callback: %f
", *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
");
    printf("x is %f
", *x);
    printf("y is %f
", *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
", 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

question from:https://stackoverflow.com/questions/65921689/how-to-update-the-value-of-a-c-output-parameter-from-python-using-a-ctypes-callb

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...