我试图通过ctypes用Python中定义的回调函数替换共享库中现有的函数指针
C中共享库的源:
#include <assert.h>
#include <stdio.h>
void (*plot)();
int c_main(int argc, void** argv) {
printf("plot is %p\n", (void*)plot);
assert(plot != NULL);
plot();
return 0;
}
Python脚本的源代码:
from sys import platform
from pathlib import Path
import ctypes
import _ctypes
FUNCTYPE = ctypes.WINFUNCTYPE if platform == 'win32' else ctypes.CFUNCTYPE
def dlclose(obj):
if platform == "win32":
_ctypes.FreeLibrary(obj._handle)
else:
_ctypes.dlclose(obj._handle)
def enc_args(args):
C_ARGS = (ctypes.POINTER(ctypes.c_char) * len(args))()
for idx, arg in enumerate(args):
C_ARGS[idx] = ctypes.create_string_buffer(arg.encode("utf-8"))
return C_ARGS
@FUNCTYPE(None)
def plotxy():
print("plotxy")
C_ARGS = enc_args([str(Path(__file__))])
CAUXDLL = ctypes.CDLL("./test.so")
print(plotxy)
print(CAUXDLL.plot)
CAUXDLL.plot = plotxy
print(CAUXDLL.plot)
print(CAUXDLL.c_main(len(C_ARGS), C_ARGS))
要测试它的脚本:
gcc -fPIC -shared -o test.so test.c
python3 test.py
我得到的输出:
# ./test.sh
<CFunctionType object at 0x7fb1f0abb1c0>
<_FuncPtr object at 0x7fb1f0abb640>
<CFunctionType object at 0x7fb1f0abb1c0>
plot is (nil)
python3: test.c:8: c_main: Assertion `plot != NULL' failed.
./test.sh: line 3: 21171 Aborted python3 test.py
因此,Python(plotxy)中定义的函数类型为CFunctionType
,而C中定义的函数指针类型为_FuncPtr
。虽然应用了CAUXDLL
中的替换,但在调用main函数时似乎没有效果
除了阅读https://docs.python.org/3/library/ctypes.html#module-ctypes,我还发现了其他问题(例如How to use typedef in ctypes或python cytpes creating callback function - Segmentation fault (core dumped)),但我找不到如何将CFunctionType
(plotxy)转换为_FuncPtr
编辑
我相信这可能不是常规使用ctypes的问题。我已经成功地做到了这一点,文档中对此做了充分的解释。这个问题超出了范围。我不想执行C函数。我希望Python用Python编写的回调函数替换现有的函数指针。请注意,可以通过使用helper C函数来实现这一点(请参见https://github.com/ghdl/ghdl-cosim/blob/master/vhpidirect/shared/pycb/caux.c#L32-L40)。因此,这个问题是关于如何在没有辅助函数的情况下实现它(如果可能的话)
从
ctypes
访问全局变量的方法是使用in_dll
,但似乎没有公开的方法来更改函数指针。我只能读它并调用它,所以我认为没有辅助函数是不可能的下面的示例更改了
int
全局变量,但是CFUNCTYPE
实例没有value
成员来更改它。我添加了一个C助手来设置全局函数来解决这个问题,并添加了一个回调的默认值来验证在更改它之前是否正确访问了它测试c:
test.py:
输出:
注意,全局指针使用
.contents
来访问它们的值,因此我尝试使用POINTER(CFUNCTYPE(None))
和plot.contents = plotxy
来访问它们的值,但这并没有正确分配全局变量,C崩溃了我甚至尝试将实际的全局指针添加到函数指针:
然后使用:
这让我可以通过
.contents
分配函数,但是c_main
仍然调用默认的绘图值。因此,使用CFUNCTYPE
作为函数参数之外的任何东西的功能似乎都没有实现相关问题 更多 >
编程相关推荐