如何用Python+ctypes向Matlab Coder生成的C函数传递结构体中的变长字符串
问题:Python通过ctypes向Matlab Coder生成的C结构体传递变长字符串失败
我能通过ctypes单独传递变长字符串给Matlab Coder生成的C代码,也能处理包含其他可变类型的复杂结构体,但结构体中的变长字符串传递始终异常——Python调用能运行,但C端获取的字符串长度错误,printf输出时程序崩溃,且可修改C代码的空间有限。
可行的单独字符串传递示例
Matlab生成的C代码
/* Function Declarations */ extern double test_string_func(const char apa_vl_data[], const int apa_vl_size[2]);
Python调用代码
import ctypes as ct import numpy as np str2_in = "hyja" bb = ct.c_char_p(str2_in.encode('utf-8')) bb_sz = np.array([1, len(str2_in)]).astype(dtype=int) bb_sz_p = bb_sz.ctypes.data libC.test_string_func.argtypes = [ct.c_char_p, np.ctypeslib.ndpointer()] dbl_out = libC.test_string_func(bb, bb_sz_p)
结构体场景的问题代码
C端结构体定义与函数声明
/* Type Definitions */ #ifndef struct_emxArray_char_T_1x10 #define struct_emxArray_char_T_1x10 struct emxArray_char_T_1x10 { char data[10]; int size[2]; }; #endif /* struct_emxArray_char_T_1x10 */ #ifndef typedef_emxArray_char_T_1x10 #define typedef_emxArray_char_T_1x10 typedef struct emxArray_char_T_1x10 emxArray_char_T_1x10; #endif /* typedef_emxArray_char_T_1x10 */ #ifndef typedef_struct0_T #define typedef_struct0_T typedef struct { double val; emxArray_char_T_1x10 str; } struct0_T; #endif /* typedef_struct0_T */ /* Function Declaration */ extern double test_string_func(const struct0_T *apa_struct);
我尝试的Python实现(存在错误)
import ctypes as ct class emxArray_char_T_1x10(ct.Structure): """ creates a struct to match emxArray_char_T_1x10 C-code from Matlab: /* Type Definitions */ #ifndef struct_emxArray_char_T_1x10 #define struct_emxArray_char_T_1x10 struct emxArray_char_T_1x10 { char data[10]; int size[2]; }; """ _fields_ = [('data', ct.c_char_p), ('size', ct.POINTER(ct.c_int))] class testInStruct(ct.Structure): """creates a struct to match struct in C file C-code from Matlab: /* Type Definitions */ typedef struct { double val; emxArray_char_T_1x10 str; } struct0_T; """ _fields_ = [ ("struct_input_val", ct.c_double), ("struct_input_str", emxArray_char_T_1x10), ] # initialise struct data input_string = "INPUT!!" input_str = emxArray_char_T_1x10() input_str.data = ct.c_char_p(input_string.encode('utf-8')) # Pass a list of int L = [1, len(input_string)] arr = (ct.c_int * len(L))() arr[:] = L input_str.size = arr sd = testInStruct() sd.struct_input_val = 2.1 sd.struct_input_str = input_str libC.test_string_func.argtypes = [ct.POINTER(testInStruct)] dbl_out = libC.test_string_func(sd)
错误原因与修正方案
核心错误
Python中定义的emxArray_char_T_1x10结构体和C端的内存布局完全不匹配:
- C端的
data是固定大小的char数组char data[10],而Python中写成了指针ct.c_char_p - C端的
size是固定大小的int数组int size[2],而Python中写成了指针ct.POINTER(ct.c_int)
这种不匹配会导致C端读取内存时出现偏移,进而获取错误的长度值,最终引发崩溃。
修正后的Python代码
import ctypes as ct # 严格匹配C端的结构体内存布局 class emxArray_char_T_1x10(ct.Structure): _fields_ = [ ('data', ct.c_char * 10), # 对应C的char data[10] ('size', ct.c_int * 2) # 对应C的int size[2] ] class testInStruct(ct.Structure): _fields_ = [ ("struct_input_val", ct.c_double), ("struct_input_str", emxArray_char_T_1x10), ] # 初始化结构体 input_string = "INPUT!!" encoded_str = input_string.encode('utf-8') input_str = emxArray_char_T_1x10() # 将字符串复制到固定数组,长度超出则截断,不足则补0 input_str.data = encoded_str.ljust(10, b'\x00')[:10] # 直接给size数组赋值 input_str.size[0] = 1 input_str.size[1] = len(encoded_str) sd = testInStruct() sd.struct_input_val = 2.1 sd.struct_input_str = input_str libC.test_string_func.argtypes = [ct.POINTER(testInStruct)] # 注意要传结构体的指针 dbl_out = libC.test_string_func(ct.byref(sd))
额外说明
你之前能处理的emxArray_real_T是动态数组结构体(用指针指向数据),但本次的emxArray_char_T_1x10是Matlab Coder生成的固定大小数组结构体,二者内存布局完全不同,不能套用同一种Python结构体定义方式。
内容的提问来源于stack exchange,提问作者SilverPy
相关产品推荐
相关产品推荐

