0

I have a vector struct in C with the following fields,

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

and there are a few functions which correspondingly act on vector instances, such as:

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);
...

and so on (mimicking a c++ style std::vector).

In other sections of my code base I have component structs, for example 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>*]
};

which, amongst others, has the following methods,

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

where one passes the address of another components' output field to these set_input methods to "connect" them.

The input and output fields of every component always store instances of struct beam - a data-type which simply stores a double complex field and a double field.


Currently I am in the process of building wrappers in Python (3.5) to call the various methods in an object-oriented to use later on for easier plotting and so forth; using ctypes to build a shared library of the C code.

The following are the wrappers that I have so far,

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

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?

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?

sjrowlinson
  • 3,297
  • 1
  • 18
  • 35
  • That `elemsize` indicates you want some generic storage. YOu should be aware you code very easily can invoke undefined behaviour. If you want to store different element, use `union`s. – too honest for this site Jan 13 '17 at 17:08
  • In the case of the `input` and `output` fields of all components, such as `mirror`, the `elemsize` will always be the same - given by `sizeof(struct beam)` (where `beam` is defined elsewhere). I do use `vector` elsewhere to store other data-types, but `input` and `output` fields always store `beam`s. – sjrowlinson Jan 13 '17 at 17:10
  • I believe the answer is "yes", but without a clear example of the attempt and the problems encountered I don't know how to direct you from here. You'd need a `class mirror(ctypes.Structure)` defined, at least, to access the `output` parameter of the `mirror` obj, and could then access the address by `ctypes.byref`. – Mark Tolonen Jan 13 '17 at 18:45
  • @MarkTolonen If I make `Mirror` inherit from `ctypes.Structure` then I will need a `_fields_` descriptor in which I give the `output` field - however the type of this field is `struct vector*` in the C-code, what would this translate to in terms of ctypes default types? `POINTER(c_ubyte)`? – sjrowlinson Jan 13 '17 at 19:55
  • @ArchbishopOfBanterbury If you just need the pointer and not access to the vector itself (which won't really work with ctypes), `c_void_p` would probably be appropriate. – Mark Tolonen Jan 13 '17 at 23:29
  • @ArchbishopOfBanterbury Oops, I forgot it wasn't a C++ vector. Define a `class vector(ctypes.Structure)` as well, and use `POINTER(vector)` as the type in the `Mirror` definition. – Mark Tolonen Jan 13 '17 at 23:44
  • @MarkTolonen I've made some updates to the question. – sjrowlinson Jan 14 '17 at 15:33

1 Answers1

1

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?

To access the output component of a Mirror given your structures:

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

To pass it to a function by reference:

>>> 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?

No, you cannot omit fields from your structure definition, or the binary layout of the underlying C structure won't be correct.

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251