【问题标题】:How to update the value of a C output parameter from python using a ctypes callback?如何使用 ctypes 回调从 python 更新 C 输出参数的值?
【发布时间】:2021-05-01 10:30:22
【问题描述】:

在 C 中,void 函数将其输出参数作为参数是很常见的。我需要使用 ctypes 回调来执行此操作,以便我可以更新指向 python 输出的指针。

C 代码:

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);
}

然后从 C 中使用它:

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);
}

哪个输出:

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

然而,在 Python 中,就我所知:

        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)

这将当前输出:

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

实际输出的位置

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

我现在尝试了许多不同的策略,包括使用ctypes.memmove,来自here 的建议和ctypes.cast,来自here 的建议。

知道我做错了什么吗?

编辑

我也试过: ct.memmove(ct.cast(x, ct.c_void_p).value, ct.cast(y, ct.c_void_p).value, ct.sizeof(ct.c_double)) 作为“问题线”

来自here

【问题讨论】:

    标签: python c callback ctypes


    【解决方案1】:

    这个 Python 回调:

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

    相当于这个C代码:

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

    你要修改的对象y的值是当前指向的,相当于C中的这个:

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

    使用以下方法更改 Python 回调中的值:

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

    【讨论】:

    • 我找到的解决方案是使用ctypes.memmove。它有效,但这是更好的解决方案。
    猜你喜欢
    • 2016-02-02
    • 1970-01-01
    • 1970-01-01
    • 2013-10-08
    • 2019-05-11
    • 1970-01-01
    • 2020-02-24
    相关资源
    最近更新 更多