1. 准备环境
- 准备开发包:包含头文件(
.h
)、库文件(.dll或.so
)及对接文档 - 安装依赖:确保Python环境已安装
ctypes
库或第三方库例如Cython
(用于复杂场景) - 配置路径:将SDK的库路径添加到环境变量或直接在代码中指定路径(推荐方式,不会因为换电脑导致无法编译,例如
sdk/windows/sdk.dll
)
2. 封装接口
加载SDK
1 | import sys |
定义结构体
1 | # 定义结构体,需要与SDK头文件一致 |
![[Python对接C库/IMG-20250327180040644.png]]
定义函数原型,需严格对齐SDK中的数据类型和函数参数顺序
1 | sdk.Init.restype = c_bool # 映射返回值,Init为C/C++中的函数名 |
3. 接口调用
函数调用
1 | sdk.Init(c_int(0), c_int_p(0), c_char_p(b"this is a test")) |
带有回调函数的函数调用
回调函数例如
1 | int (*Callback) (int, char*); |
Python中定义回调函数类型
1 | CallbackType = CFUNCTYPE(c_int, c_int, c_char_p) # 返回类型在前,参数在后 |
若C函数使用__stdcall
(常见于Windows API),需要WINFUNCTYPE
替代CFUNCTYPE
,若为__cdecl
(默认),则使用CFUNCTYPE
Python实现回调函数(参数和返回值需与C定义严格一致)
1 | def py_callback(num, text) -> int: |
处理指针参数
若回调参数包含指针,例如void*
,需要使用c_void_p
类型,并通过cast解析
1 | def py_callback(data_ptr): |
注册回调函数
1 | c_callback = CallbackType(py_callback) # 使用定义的回调类型包装Python函数 |
4. 资源释放
退出时需要调用SDK中的清理函数释放资源
1 | sdk.Cleanup() |
5. 注意事项
- 结构体指针和缓冲区需要手动分配/释放,避免内存泄漏
- 不同版本SDK接口可能有差异,建议统一开发与部署环境
- 映射Windows中特有的类型例如
WORD
,DWORD
在wintypes
包中 - C调用Python回调时,若Python函数抛出异常可能导致程序崩溃。需要在回调内部处理异常。
- 若C函数在子线程中调用回调,需确保Python的GIL(全局解释锁)已获取
1
2
3
4
5
6
7from ctypes import py_object, pythonapi
PyGILState_Ensure = pythonapi.PyGILState_Ensure
PyGILState_Release = pythonapi.PyGILState_Release
def thread_safe_callback():
state = PyGILState_Ensure()
# 执行Python操作
PyGILState_Release(state)