如何使用 ctypes 回调从 python 更新 C 输出参数的值?
How to update the value of a C output parameter from python using a ctypes callback?
在 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 , a suggestion from here and ctypes.cast, a suggestion from 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回调:
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
的值是current指向的,相当于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
在 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 , a suggestion from here and ctypes.cast, a suggestion from 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回调:
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
的值是current指向的,相当于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