1

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.

7
  • Use "ii" instead of "OO" to get integers. Commented Aug 22, 2022 at 16:57
  • How would I have the (5, 4) and (7, 1) be created as structs though? Commented Aug 22, 2022 at 16:59
  • I was confused, I was thinking you were parsing each element of the tuple. Commented Aug 22, 2022 at 17:00
  • I probably didn't make it clear enough, I wanted the input tuples to be converted into the Point structs. Commented Aug 22, 2022 at 17:03
  • You're clear, it was my own mistake. Commented Aug 22, 2022 at 17:04

1 Answer 1

0

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.
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your detailed comment explaining why my code didn't work, how to solve it and how the correct solution works. Its really appreciated.

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.