ctypes:公开在 C 中 malloc 的结构数组
ctypes: exposing array of structs malloc'ed in C
看过这个问题:
现在我正在尝试实现我的解决方案版本,但是 struct Arr
中 len_a
的输出与 C 中的设置方式不同。我的问题是:什么是将 Parse.arr
设置为 python 中的 Arr
对象数组的正确方法(在 C 中最初是 allocated/set)? pylink.py.
中的self.arr = cast(byref(self.parse.arr),POINTER(Arr*n)).contents
行明显不正确
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
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()
输出
[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
通过替换 pylink.py
中的这一行解决了这个问题
self.arr = cast(byref(self.parse.arr), POINTER(Arr*n)).contents
和
self.arr = cast(self.parse.arr, POINTER(Arr*n)).contents
属性 arr
声明为 POINTER(Arr)
,因此函数 byref
在这里无效。我的实现与问题中链接的实现之间的一个重要区别是如何声明结构数组。我的是指针,而另一个使用零大小的数组。有关详细信息,请参阅:https://docs.python.org/3/library/ctypes.html#ctypes.byref
看过这个问题:
现在我正在尝试实现我的解决方案版本,但是 struct Arr
中 len_a
的输出与 C 中的设置方式不同。我的问题是:什么是将 Parse.arr
设置为 python 中的 Arr
对象数组的正确方法(在 C 中最初是 allocated/set)? pylink.py.
self.arr = cast(byref(self.parse.arr),POINTER(Arr*n)).contents
行明显不正确
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
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()
输出
[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
通过替换 pylink.py
中的这一行解决了这个问题self.arr = cast(byref(self.parse.arr), POINTER(Arr*n)).contents
和
self.arr = cast(self.parse.arr, POINTER(Arr*n)).contents
属性 arr
声明为 POINTER(Arr)
,因此函数 byref
在这里无效。我的实现与问题中链接的实现之间的一个重要区别是如何声明结构数组。我的是指针,而另一个使用零大小的数组。有关详细信息,请参阅:https://docs.python.org/3/library/ctypes.html#ctypes.byref