简体   繁体   中英

How to pass a struct from python to a ctypes function in a shared object?

I'm trying to create something similar to numpy to learn how ctypes work and I ran into a problem with passing a pointer to a "Matrix" struct to some functions.

The output of calling print_matrix would always be some random integer and then a few spaces.

I'm using Python 3.7.5 and the C code was compiled using: gcc -shared -o libarray.so -fPIC array.c

C Code:

typedef struct Matrix {
        int *arr;
        int *shape;
        int dims;
} Matrix;

void print_matrix(Matrix *Mat) {
        int num = 1;
        for (int i = 0; i < Mat -> dims; i++) {num *= Mat -> shape[i];}

        for (int i = 0; i < num; i++) {
                printf("%d  ", Mat -> arr[i]);
                if (Mat -> dims >= 2) {
                        if (((i + 1) % Mat -> shape[0]) == 0) {
                                printf("\n");
                        }
                } 
        }
}

Python Code:

import ctypes as cty

class Matrix(cty.Structure):
    _fields_ = [("arr", cty.POINTER(cty.c_int)), ("shape", cty.POINTER(cty.c_int)), ("dims", cty.c_int)]

libarray = cty.CDLL("./libarray.so")

print_matrix = libarray.print_matrix
print_matrix.restype = None
print_matrix.argtypes = [Matrix]

mat = Matrix((cty.c_int * 4)(*[1, 2, 3, 4]), (cty.c_int * 2)(*[2, 2]), cty.c_int(2))
print_matrix(mat)

I know that for this function, I can just pass the Matrix struct directly by change the print_matrix code, but because of some other things in my code, I want to deal mostly with pointers. Sorry for this weird restriction and thanks in advance.

The problem is that in C, you have void print_matrix(Matrix *Mat) , but in Python, you have print_matrix.argtypes = [Matrix] . Python is passing a Matrix , but C is expecting a Matrix * . It doesn't matter which one you use, but they have to agree.

If you want to pass a Matrix , then leave your Python code alone and change your C code to this:

#include <stdio.h>

typedef struct Matrix {
        int *arr;
        int *shape;
        int dims;
} Matrix;

void print_matrix(Matrix Mat) {
        int num = 1;
        for (int i = 0; i < Mat.dims; i++) {num *= Mat.shape[i];}

        for (int i = 0; i < num; i++) {
                printf("%d  ", Mat.arr[i]);
                if (Mat.dims >= 2) {
                        if (((i + 1) % Mat.shape[0]) == 0) {
                                printf("\n");
                        }
                } 
        }
}

I changed Matrix *Mat to Matrix Mat and -> to . .

If you want to pass a Matrix * , then leave your C code alone and change your Python code to this:

import ctypes as cty

class Matrix(cty.Structure):
    _fields_ = [("arr", cty.POINTER(cty.c_int)), ("shape", cty.POINTER(cty.c_int)), ("dims", cty.c_int)]

libarray = cty.CDLL("./libarray.so")

print_matrix = libarray.print_matrix
print_matrix.restype = None
print_matrix.argtypes = [cty.POINTER(Matrix)]

mat = Matrix((cty.c_int * 4)(*[1, 2, 3, 4]), (cty.c_int * 2)(*[2, 2]), cty.c_int(2))
print_matrix(cty.byref(mat))

I changed [Matrix] to [cty.POINTER(Matrix)] and mat to cty.byref(mat) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM