使用SWIG生成Python绑定:多字节OUTPUT参数报错排查
问题描述
我有一个C库,包含3个以**编译时固定长度的uint8_t***作为参数的函数,参数组合分别是:
- 仅含2个输出参数
- 1个输入+2个输出参数
- 2个输入+1个输出参数
尝试用SWIG生成Python绑定,已经导入typemaps.i,但调用时仍报错:bytearray不适用于uint8_t INOUT[]参数,函数调用失败。已经排除使用%pybuffer_mutable_binary(因为需要额外的尺寸参数,不符合编译时固定长度的场景)。
错误信息示例:
TypeError: in method 'func_name', argument X of type 'uint8_t INOUT[]'
解决方案
问题根源是默认的typemaps.i没有针对编译时固定长度数组生成适配Pythonbytearray的类型映射,默认INOUT映射依赖运行时尺寸传递,和你的场景不匹配。以下是具体解决方法:
1. 自定义固定长度数组的SWIG类型映射
针对每个固定长度的uint8_t数组,手动编写类型映射,直接对接Python的bytearray或bytes。
假设你的C函数定义(以1个输入+2个输出、数组长度16为例):
#include <stdint.h> void func1(uint8_t in[16], uint8_t out1[16], uint8_t out2[16]);
在SWIG接口文件(.i)中添加:
%module mylib %{ #include "mylib.h" %} // 输入型固定长度uint8_t数组映射 %typemap(in) uint8_t INPUT[16] { if (!PyBytes_Check($input) && !PyByteArray_Check($input)) { PyErr_SetString(PyExc_TypeError, "参数需为bytes或bytearray类型"); return NULL; } if (PyObject_Length($input) != 16) { PyErr_SetString(PyExc_ValueError, "参数长度必须为16字节"); return NULL; } if (PyBytes_Check($input)) { memcpy($1, PyBytes_AS_STRING($input), 16); } else { memcpy($1, PyByteArray_AS_STRING($input), 16); } } // 输出型固定长度uint8_t数组映射 %typemap(out) uint8_t OUTPUT[16] { $result = PyByteArray_FromStringAndSize((char*)$1, 16); } // 声明函数时标记参数类型 void func1(uint8_t INPUT[16], uint8_t OUTPUT[16], uint8_t OUTPUT[16]);
Python调用示例:
import mylib # 准备输入 in_data = bytearray(range(16)) # 调用函数,直接获取输出 out1, out2 = mylib.func1(in_data)
2. 用%array_class生成固定长度数组包装类
SWIG的%array_class指令可以为固定长度数组生成专用Python类,彻底避免类型不匹配:
SWIG接口文件配置:
%module mylib %{ #include "mylib.h" %} // 生成uint8_t[16]的Python包装类 %array_class(uint8_t, UInt8Array16); // 直接声明C函数 void func1(uint8_t in[16], uint8_t out1[16], uint8_t out2[16]);
Python调用示例:
import mylib # 创建输入、输出数组对象 in_arr = mylib.UInt8Array16() out1_arr = mylib.UInt8Array16() out2_arr = mylib.UInt8Array16() # 填充输入数据 for i in range(16): in_arr[i] = i # 调用函数 mylib.func1(in_arr, out1_arr, out2_arr) # 转换为bytearray获取结果 result1 = bytearray(out1_arr) result2 = bytearray(out2_arr)
3. 修正函数声明的SWIG识别
如果你的C函数声明是void func(uint8_t* in)(而非uint8_t in[16]),SWIG会将其视为通用指针,无法识别固定长度。这时候需要在SWIG接口中显式绑定长度:
%apply uint8_t INPUT[16] { uint8_t* in }; %apply uint8_t OUTPUT[16] { uint8_t* out1, uint8_t* out2 };
内容的提问来源于stack exchange,提问作者JamesTheAwesomeDude
相关产品推荐
相关产品推荐

