简体   繁体   English

ctypes:公开在C中分配的结构体数组

[英]ctypes: exposing array of structs malloc'ed in C

Having looked at this question: 看了这个问题:

ctypes: How do I define an array of a structure as a field of another structure? ctypes:如何将一个结构的数组定义为另一个结构的字段?

now I'm trying to implement my version of the solution, but the output of len_a in struct Arr is different from how is it set in C. My question is: what is the proper way to set Parse.arr as an array of Arr objects in python (which is originally allocated/set in C)? 现在我正在尝试实现该解决方案的版本,但是struct Arrlen_a的输出与len_a中的设置不同。我的问题是:将Parse.arr设置为Arr数组的正确方法是什么? python中的对象(最初是在C中分配/设置的)? There is something obviously incorrect on the line self.arr = cast(byref(self.parse.arr),POINTER(Arr*n)).contents in pylink.py . 也有一些是上线显然是不正确self.arr = cast(byref(self.parse.arr),POINTER(Arr*n)).contentspylink.py。

clink.c 链接

#include <stdio.h>
#include <stdlib.h>
#define SIZE 10

struct Arr {
    int len_a;
};

struct Parse {
    struct Arr* arr;
    int len_arr;
};

struct Parse* C_new_domain(void) {
    int i = 0;
    struct Parse* parse = malloc(sizeof(struct Parse));   
    parse->arr = malloc(SIZE*sizeof(struct Arr));
    for (i=0 ; i<SIZE ; i++) {
        parse->arr[i].len_a = i;
    }
    parse->len_arr = SIZE;
    return parse;
}

void C_end_program(struct Parse* parse) {
    free(parse->arr);
    free(parse);
    return;
}

pylink.py pylink.py

import sys
from ctypes import *
_lib = cdll.LoadLibrary('./libclink.so')

class Arr(Structure):
    def __init__(self, obj, name=""):
        self.obj = obj
    _fields_ = [("len_a", c_int)]


class Parse(Structure):
    def __init__(self, obj, name=""):
        self.obj = obj
    _fields_ = [("arr", POINTER(Arr)),
                ("len_arr", c_int)]

class Domain(object):
    domain = POINTER(Parse)
    parse = None
    arr = None
    _lib.C_new_domain.argtype = None
    _lib.C_new_domain.restype = POINTER(Parse)
    _lib.C_end_program.argtype = POINTER(Parse)
    def __init__(self):
        self.domain = _lib.C_new_domain()
        self.parse = self.domain.contents
        n = self.parse.len_arr
        self.arr = cast(byref(self.parse.arr),POINTER(Arr*n)).contents
    def end(self):
        _lib.C_end_program(self.domain)

if __name__ == '__main__':
    domain = Domain()
    for count, array in enumerate(domain.arr):
        print "[Hoping this is %d] --> array[%d].len_a is %d"%(count, count, array.len_a)
    domain.end()

Output 输出量

[Hoping this is 0] --> array[0].len_a is 25023216
[Hoping this is 1] --> array[1].len_a is 0
[Hoping this is 2] --> array[2].len_a is 10
[Hoping this is 3] --> array[3].len_a is 32512
[Hoping this is 4] --> array[4].len_a is 14962
[Hoping this is 5] --> array[5].len_a is 0
[Hoping this is 6] --> array[6].len_a is 33
[Hoping this is 7] --> array[7].len_a is 0
[Hoping this is 8] --> array[8].len_a is 10
[Hoping this is 9] --> array[9].len_a is 0

This was solved by replacing this line in pylink.py 这是通过替换pylink.py中的这一行来解决的

self.arr = cast(byref(self.parse.arr), POINTER(Arr*n)).contents

with

self.arr = cast(self.parse.arr, POINTER(Arr*n)).contents

The attribute arr is declared as a POINTER(Arr) , so function byref is not valid here. 属性arr被声明为POINTER(Arr) ,因此功能byref在这里无效。 An important distinction between my implementation the one linked in the question is how the structure arrays are declared. 我的实现与问题中链接的实现之间的重要区别是如何声明结构数组。 Mine is a pointer, whereas the other uses a zero-sized array. 我的是一个指针,而另一个使用零大小的数组。 For more info see: https://docs.python.org/3/library/ctypes.html#ctypes.byref 有关更多信息,请参见: https : //docs.python.org/3/library/ctypes.html#ctypes.byref

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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