You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 13:49:53