Python绑定C++回调函数出现参数异常问题求助
问题排查:C++回调函数的Python绑定参数异常
问题背景
尝试为C回调函数编写Python绑定,C回调定义如下:
typedef enum { CB_Event_TermRegister = 101, ... }enSdkCbType; typedef enum { TSDK_DEV_TYPE_UNDEF = 0, ... }enSdkDevType; typedef struct { enSdkDevType eTermType; ... }TSdkEventTermRegister; typedef int (CALLBACK* ON_CTS_SDK_CALL_BACK)(enSdkCbType eCbType, LPVOID pParam, DWORD dwSize, int usr_data);
Python中用ctypes实现的绑定运行时出现参数异常:传入参数顺序、类型不符,多了一个enSdkCbType对象,导致判断逻辑失效。
错误分析与修正
1. CFUNCTYPE参数列表不完整
C++回调函数包含4个参数,但你的Python代码中定义CallbackType时只指定了3个参数类型,缺少最后一个int类型的usr_data,这会导致ctypes解析参数栈时出现偏移,参数顺序完全混乱。
2. 枚举类型的定义与使用问题
在ctypes中,C++的枚举本质是int类型,直接用自定义的enSdkCbType类(继承c_int)作为CFUNCTYPE的参数类型可能导致参数解析异常,出现多余的对象。建议直接用c_int替代自定义枚举类作为参数类型,判断时直接使用常量值即可。
3. 判断常量笔误
回调函数中判断的CB_Asw_OpenTermAudVid与C++定义的CB_Event_TermRegister不匹配,属于笔误,会导致逻辑永远不触发。
修正后的Python代码
from ctypes import * # 定义枚举常量(直接用整型常量即可,无需继承c_int) CB_Event_TermRegister = 101 TSDK_DEV_TYPE_UNDEF = 0 class TSdkEventTermRegister(Structure): _fields_ = [ ("eTermType", c_int), # 直接用c_int对应C++的enSdkDevType ... ] def callback(eCbType, pParam, dwParamLen, usr_data): if eCbType == CB_Event_TermRegister: assert dwParamLen == sizeof(TSdkEventTermRegister) # 转换指针到结构体 p = cast(pParam, POINTER(TSdkEventTermRegister)) print(p.contents.eTermType) return 0 dll = CDLL('my_dll') # 修正CFUNCTYPE的参数列表:返回值c_int,四个参数依次为c_int, c_void_p, c_ulong, c_int CallbackType = CFUNCTYPE(c_int, c_int, c_void_p, c_ulong, c_int) # 注意:必须保留回调对象的引用,避免被Python垃圾回收机制回收 callback_obj = CallbackType(callback) dll.func(callback_obj)
额外注意事项
- 必须保留回调对象的引用(比如
callback_obj),否则Python的垃圾回收机制可能会在回调被触发前回收该对象,导致程序崩溃。 - 结构体中的枚举类型直接用
c_int对应即可,因为C++枚举在底层是整型,无需额外封装类。
内容的提问来源于stack exchange,提问作者肉蛋充肌
相关产品推荐
相关产品推荐

