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

时间:2017-01-13 17:03:03

标签: python c ctypes python-c-extension

我在C中有一个vector结构,包含以下字段,

struct vector {
    unsigned char* data;
    unsigned long size;
    unsigned long elemsize;
    unsigned long capacity;
};

并且有一些函数相应地作用于vector个实例,例如:

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::vector)。

在我的代码库的其他部分中,我有组件结构,例如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>*]
};

其中包括以下方法,

struct mirror* mirror_alloc();
int mirror_init(double R, double T, struct mirror* mrr);
// ibn is the "initial-beam-number"
void mirror_set_left_input(struct vector** input, unsigned long ibn, struct mirror* mrr);
void mirror_set_right_input(struct vector** input, unsigned long ibn, struct mirror* mrr);

其中一个人传递了另一个组件的地址&#39;这些output方法的set_input字段为&#34; connect&#34;它们。

每个组件inputoutput字段始终存储struct beam的实例 - 一种只存储double complex字段的数据类型和double字段。

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

以下是我到目前为止的包装,

vector_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)]

mirror_wrapper.py

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)]

有什么方法可以获取某个组件的output字段的地址(例如mirror),其类型为struct vector**,并将其传递给,例如,某些函数Mirror.set_left_input作为input参数?

另外,我假设有必要在py结构的_fields_中创建与C结构中的字段相对应的所有字段 - 即是否可以省略该描述符中的某些字段?

1 个答案:

答案 0 :(得分:1)

  

有没有办法可以获得某个组件(比如镜像)的输出字段的地址,它具有类型struct vector **,并将其传递给,例如某个函数Mirror.set_left_input作为输入参数?

根据您的结构访问Mirror的输出组件:

>>> m = Mirror()
>>> m.output[0]
<__main__.LP_Vector object at 0x00000199607CA0C8>

通过引用将其传递给函数:

>>> mirror_set_left_input(byref(m.output[0]),...)
  

另外,我假设有必要在对应于C结构中的字段的python结构的 fields 中创建所有字段 - 即是否可以省略此描述符中的某些字段?

不,您不能省略结构定义中的字段,或者底层C结构的二进制布局不正确。