使用Python和ctypes将结构中的可变长度字符串传递给c函数(由Matlab Coder生成)

bvjveswy  于 2023-04-12  发布在  Matlab
关注(0)|答案(2)|浏览(163)

我试图将Python结构中的可变大小字符串传递到C代码中(或者更确切地说,传递到DLL/SO中)。C代码是由Matlab Coder生成的,因此我相当局限于更改C代码(尽管可以在Matlab中进行一些调整以更改输出)。
我在Python中使用ctypes来创建包含各种元素的结构,这是有效的,传递包含可变长度字符串的变量也是如此,但是,我不能让一个可变长度的字符串在一个结构中工作。
当在Matlab中创建字符串输入时,传递字符串效果很好。我通过ctypes将字符串传递到C类型定义中,如下所示:
Matlab生成的C代码:

/* Function Declarations */
extern double test_string_func(const char apa_vl_data[],
                               const int apa_vl_size[2]);

Python:

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)

但是,当我在Matlab(C和Python)中创建一个结构体时,我无法使调用工作:
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 */

从头文件:

extern double test_string_func(const struct0_T *apa_struct);

我在Python中尝试过的许多方法之一:

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)

我已经成功地使相当复杂的结构工作,用不同的类型和数组作为输入。但是在结构中传递字符串时出错的原因我不知道。

更新:忘了说C代码在Python中调用时运行,但在C代码中产生不正确的字符串长度,并在C代码中尝试“fprintf”传递的字符串时退出代码。

你知道我会做错什么吗?
顺便说一下,这是具有可变长度变量的结构的标准格式,并且这些变量很容易处理:

struct emxArray_real_T
{
  double *data;
  int *size;
  int allocatedSize;
  int numDimensions;
  boolean_T canFreeData;
};
u4dcyp6a

u4dcyp6a1#

Chris Luengo建议的更改有效,但需要进行一些额外的修改以使所有内容都能正常工作。如下所示:
emxArray_char_T_1x10部分应为:

class emxArray_char_T_1x10(ct.Structure):
      _fields_ = [('data', ct.c_char * 10),
                  ('size', ct.c_int * 2))]

而“initialize struct data”部分应该重新编写如下:

# initialise struct data
input_string = "INPUT!!"

input_str = emxArray_char_T_1x10()
arr_1 = bytes(input_string, 'utf-8')

input_str.data = arr_1
9rbhqvlz

9rbhqvlz2#

C结构体

struct emxArray_char_T_1x10 {
  char data[10];
  int size[2];
};

应该与Python中的Ctypes匹配为

class emxArray_char_T_1x10(ct.Structure):
    _fields_ = [('data', ct.c_char * 10),
                ('size', ct.POINTER(ct.c_int))]

注意char* achar b[10]的区别。是的,b可以被看作是指向数组第一个元素的指针,但结构包含实际的数组,10个字符,而不是一个指向字符的指针。

相关问题