Home > OS >  Accessing struct data through a pointer in a Python C extension
Accessing struct data through a pointer in a Python C extension

Time:08-24

So I'm trying to create a C extension and am having a bit of trouble accessing the struct data for one of my arguments. Here's my current code:

#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <numpy/arrayobject.h>
#include <stdio.h>
#include <stdlib.h>


typedef struct Point {
    int x;
    int y;
} Point;


static PyObject *test(PyObject *self, PyObject *args) {
    Point *start, *end = NULL;
    if(!PyArg_ParseTuple(args, "OO", &start, &end)) {
        return NULL;
    }

    printf("%d %d\n", (int)start->x, (int)start->y);
    printf("%d %d\n", (int)end->x, (int)end->y);

    return PyLong_FromLong(0);
}

Python code which calls it:

import testmodule

testmodule.test((5, 4), (7, 1))

I'm trying to get these inputs tuples to be converted into Point structs so they can be used further on in the program. Any idea how I can fix this?

Any help would be appreciated.

CodePudding user response:

You expect too much from PyArg_ParseTuple: its implementation knows nothing about the Point-struct which is defined by you - it has no idea how a tuple can be converted to a Point struct.

You have to provide the following information to PyArg_ParseTuple:

  • arguments consist of two tuples
  • each tuple has two integers inside
  • first integer in the first tuple maps to start.x, second - to start.y
  • first integer in the first tuple maps to end.x, second - to end.y

This all can be achieved with the following code:

    static PyObject *test(PyObject *args) {
        Point start, end;
        if(!PyArg_ParseTuple(args, "(ii)(ii)", &start.x, &start.y, 
                                               &end.x, &end.y)) {
            return NULL;
        }

        printf("%d %d\n", start.x, start.y);
        printf("%d %d\n", end.x, end.y);

        return PyLong_FromLong(0);
    }
    """

As you can see:

  • PyArg_ParseTuple will not allocate memory it writes values to existing memory, thus start and end are allocated on stack and aren't pointers.
  • "(ii)(ii)" tells to look for two tuples ((...)` means tuple), each consisting of two integers.
  • we give the addresses where the converted integer values should be stored, e.g. &start.x.
  • Related