使用ctypes从Python中获取C中自定义数据类型的地址

使用ctypes从Python中获取C中自定义数据类型的地址,python,c,ctypes,python-c-extension,Python,C,Ctypes,Python C Extension,我在C中有一个向量结构,带有以下字段 struct vector { unsigned char* data; unsigned long size; unsigned long elemsize; unsigned long capacity; }; 还有一些函数相应地作用于向量实例,例如: struct vector* vector_new(unsigned long elemsize); void vector_delete(struct vector*

我在C中有一个
向量
结构,带有以下字段

struct vector {
    unsigned char* data;
    unsigned long size;
    unsigned long elemsize;
    unsigned long capacity;
};
还有一些函数相应地作用于
向量
实例,例如:

struct vector* vector_new(unsigned long elemsize);
void vector_delete(struct vector* vec);
void vector_push_back(struct vector* vec, void* value, unsigned long elemsize);
void vector_reserve(struct vector* vec, unsigned long cap);
...

等(模仿C++风格<代码> STD::向量< /代码>).< 在代码库的其他部分,我有组件结构,例如

mirror

struct mirror {
    double R;
    double T;
    // extra fields omitted - see mirror_wrapper.py below
    struct vector* input[2]; // [vector<beam>*, vector<beam>*]
    struct vector* output[2]; // [vector<beam>*, vector<beam>*]
};
其中一个将另一个组件的
输出
字段的地址传递给这些
设置输入
方法以“连接”它们

每个组件的
输入
输出
字段始终存储
结构梁
的实例,该数据类型仅存储一个
双复数
字段和一个
字段


目前,我正在用Python(3.5)构建包装器,以调用面向对象中的各种方法,以便以后更容易地绘制等等;使用ctypes构建C代码的共享库

以下是我到目前为止所用的包装纸

vector\u wrapper.py

from ctypes import cdll
from ctypes import Structure
from ctypes import c_ubyte
from ctypes import c_ulong
from ctypes import POINTER

class Vector(structure):
    _fields_ = [
        ("data", POINTER(c_ubyte)),
        ("size", c_ulong),
        ("elemsize", c_ulong),
        ("capacity", c_ulong)]
from ctypes import cdll
from ctypes import Structure
from ctypes import byref
from ctypes import c_double
from ctypes import c_ubyte
from ctypes import c_ulong
from ctypes import c_bool
from ctypes import POINTER
from ctypes import pointer
from vector_wrapper import Vector
lib = cdll.LoadLibrary('./ctn_lib.so')

class Mirror(Structure):
    _fields_ = [
        ("R", c_double),
        ("T", c_double),
        ("pR", c_double),
        ("pT", c_double),
        ("tuning", c_double),
        ("mass", POINTER(c_double)),
        ("last_time", c_double),
        ("net_force", c_double),
        ("dfcoeff", c_double),
        ("phfcoeff", c_double*2), #phfcoeff is a double complex in c code
        ("rpfcoeff", c_double),
        ("input", POINTER(Vector)*2),
        ("output", POINTER(Vector)*2),
        ("has_left_input", c_bool),
        ("has_right_input", c_bool)]
mirror\u wrapper.py

from ctypes import cdll
from ctypes import Structure
from ctypes import c_ubyte
from ctypes import c_ulong
from ctypes import POINTER

class Vector(structure):
    _fields_ = [
        ("data", POINTER(c_ubyte)),
        ("size", c_ulong),
        ("elemsize", c_ulong),
        ("capacity", c_ulong)]
from ctypes import cdll
from ctypes import Structure
from ctypes import byref
from ctypes import c_double
from ctypes import c_ubyte
from ctypes import c_ulong
from ctypes import c_bool
from ctypes import POINTER
from ctypes import pointer
from vector_wrapper import Vector
lib = cdll.LoadLibrary('./ctn_lib.so')

class Mirror(Structure):
    _fields_ = [
        ("R", c_double),
        ("T", c_double),
        ("pR", c_double),
        ("pT", c_double),
        ("tuning", c_double),
        ("mass", POINTER(c_double)),
        ("last_time", c_double),
        ("net_force", c_double),
        ("dfcoeff", c_double),
        ("phfcoeff", c_double*2), #phfcoeff is a double complex in c code
        ("rpfcoeff", c_double),
        ("input", POINTER(Vector)*2),
        ("output", POINTER(Vector)*2),
        ("has_left_input", c_bool),
        ("has_right_input", c_bool)]
是否有任何方法可以获取某个组件的
输出
字段的地址(例如
镜像
),该组件的类型为
结构向量**
,并将其传递给某个函数
镜像。将左输入
设置为
输入
参数

此外,我假设有必要在python结构的
\u fields\uu
中创建与C结构中的字段相对应的所有字段,也就是说,是否可以从这个描述符中省略一些字段

是否有任何方法可以获取某个组件(例如镜像)的输出字段的地址,该组件的类型为struct vector**,并将其传递给某个函数mirror.set_left_input作为输入参数

要访问给定结构的镜像的输出组件,请执行以下操作:

>>> m = Mirror()
>>> m.output[0]
<__main__.LP_Vector object at 0x00000199607CA0C8>
此外,我假设有必要在python结构的字段中创建与C结构中的字段相对应的所有字段,也就是说,是否可以从这个描述符中省略一些字段


不,不能从结构定义中省略字段,否则底层C结构的二进制布局将不正确。

elemsize
表示需要一些通用存储。您应该知道,您的代码很容易调用未定义的行为。如果要存储不同的元素,请使用
union
s。对于所有组件(如
mirror
)的
input
output
字段,
elemsize
将始终相同-由
sizeof(struct beam)
给出(其中
beam
在别处定义)。我确实在其他地方使用
vector
来存储其他数据类型,但是
input
output
字段总是存储
beam
s。我相信答案是“是”,但没有明确的尝试示例和遇到的问题,我不知道如何从这里指导您。您至少需要定义一个
类镜像(ctypes.Structure)
来访问
镜像
对象的
输出
参数,然后可以通过
ctypes.byref
@MarkTolonen访问地址如果我让
Mirror
ctypes.Structure
继承,那么我需要一个
\u字段
描述符,在其中我给出
输出
字段-但是这个字段的类型是
struct vector*
,在C代码中,就ctypes默认类型而言,这意味着什么
POINTER(c_ubyte)
?@archbishopfanterbury如果您只需要指针,而不需要访问向量本身(这在ctypes中并不真正起作用),
c_void\u p
可能是合适的。目前看来还可以,需要进行更彻底的测试,但应该很好-再次干杯!