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

Obtaining address of custom data-type in C from Python using ctypes

我在 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);

将另一个组件的 output 字段的地址传递给这些 set_input 方法 "connect" 它们。

每个组件的 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)]

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

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

Is there any way in which I can get the address of an output field of some component (say a mirror), which has the type struct vector**, and pass this to, e.g., some function Mirror.set_left_input as the input parameter?

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

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

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

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

Also, I assume it is necessary to create all fields in the fields of a python structure corresponding to the fields in the C structs - i.e. is it possible to omit some fields from this descriptor or not?

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