2

I have an structure in c as follows

typedef struct _person{
         int id[10];
         int number[10];
}person;

How can one bind this using pybind11?

1 Answer 1

5

There does not seem to be a pretty way AFAICT when you want the data to be writable (it's somewhat less contrived when the data would be readonly). Anyway, the following does the trick, assuming you have numpy installed:

#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
#include <pybind11/numpy.h>


typedef struct _person{
    int id[10];
    int number[10];
} person;

PYBIND11_MODULE(person, m)
{   
    pybind11::class_<person>(m, "person", pybind11::buffer_protocol())
        .def(pybind11::init<>())
        .def_property("id", [](person &p) -> pybind11::array {
            auto dtype = pybind11::dtype(pybind11::format_descriptor<int>::format());
            auto base = pybind11::array(dtype, {10}, {sizeof(int)});
            return pybind11::array(
                dtype, {10}, {sizeof(int)}, p.id, base);
        }, [](person& p) {})
        .def_property("number", [](person &p) -> pybind11::array {
            auto dtype = pybind11::dtype(pybind11::format_descriptor<int>::format());
            auto base = pybind11::array(dtype, {10}, {sizeof(int)});
            return pybind11::array(dtype, {10}, {sizeof(int)}, p.number, base);
        }, [](person& p) {});
}

The ticket is to provide the empty base object which makes the array behave as a view object. Without the base, it makes a copy. You do not need the property setter (that would, if implemented, set the array, not the array items) and could raise an error instead of providing the no-op as I did. Also, if you really have two same-sized arrays, you can use a helper function instead of the lambdas.

The basic problem for binding C builtin arrays is that python does not have a proper array type (there is a basic memory view and the module array, but no true array type), hence you need to get one from somewhere and pybind11 prefers to take the one from numpy as it's the best game in town.

Just to show you an alternative, in cppyy (http://cppyy.org), I took a different tack: it has a low-level array view, which can subsequently be handed to numpy for view or copying as desired, since it implements the full buffer protocol. The advantage here is that it's the python user who can decide on the final use. The disadvantage is that if you're going to use numpy anyway, it's an extra step. But it's also directly usable without numpy installed:

import cppyy

cppyy.cppdef("""
typedef struct _person{
    int id[10];
    int number[10];
} person;
""")

p = cppyy.gbl.person()
print(len(p.id), p.id)
print(list(p.id))

which produces:

(10, <cppyy.LowLevelView object at 0x105ab33b0>)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Sign up to request clarification or add additional context in comments.

2 Comments

This answer is made of pure gold !
@Wim can you kindly take a look in this question. I have tried to follow your answer but failed. I guess it is for std::array`.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.