2

I am trying to learn to use ctypes to populate a linked list of C structs and return the head of the list to Python for post processing. To do that, I have a simple C struct, defined like so:

struct Checkpoint
{
     double *state;
     struct Checkpoint *next;
};
typedef struct Checkpoint checkpoint;

And I have a simple matching Python 3 class defined like so:

class Checkpoint(ct.Structure):
    pass
Checkpoint._fields_ = [('state', ct.POINTER(ct.c_double)),
                       ('next', ct.POINTER(Checkpoint))]

After calling the C code via ctypes to populate a few examples of this structure, I try to print the values in the state array on the python side.

def main():
    # Load the shared library into c types.
    libc = ct.CDLL("./structs.so")
    entry = wrap_function(libc, 'pymain', ct.POINTER(Checkpoint), None)
    get_state = wrap_function(libc, 'get_state', ct.POINTER(ct.c_double), [ct.POINTER(Checkpoint)])
    get_next = wrap_function(libc, 'get_next', ct.POINTER(Checkpoint), [ct.POINTER(Checkpoint)])
    start = entry()
    print(get_state(start).contents);
    start = get_next(start)
    print(get_state(start).contents);

The get_state and get_next functions are as follows:

double *get_state(checkpoint *current)
{
    return current->state;
}

checkpoint *get_next(checkpoint *current)
{
    return current->next;
}

These functions are returning a reference to the correct memory, but I am having trouble accessing anything beyond the first element of the arrays in the structs so defined.

Two questions:

  1. Do I need the get_state and get_next functions, or can I access those parameters directly in Python without doing a call back to C after my structures are defined and populated? If so, how?

  2. My main function in python works to populate the structures as I want them, but only the first value of the state array is printed by the print calls. How to I access the rest of the values in the array?

1 Answer 1

1

To answer your first question, I believe the get_state and get_next are not necessary, as you can access the fields of Checkpoint directly

start = entry()
state = start.contents.state
next = start.contents.next

As for the second question, in the case of pointers, .contents will provide the value stored at the pointer's memory address. This means it will only print the first item in the array instead of the entire array. To print the entire array, you must loop through it, printing each element. When only using the pointer, the array's size is unknown, so the first step is to store this count. I think the Checkpoint struct would be a good location.

struct Checkpoint
{
     double *state;
     int state_len;
     struct Checkpoint *next;
};
typedef struct Checkpoint checkpoint;

Then, you'll need to update the python class

class Checkpoint(ct.Structure):
    pass
Checkpoint._fields_ = [('state', ct.POINTER(ct.c_double)),
                       ('state_len', ct.c_int),
                       ('next', ct.POINTER(Checkpoint))]

I'm not sure where your state array is populated, but you'll need to update the state_len wherever you add elements.

Once this is done, you should be able to print the contents using a loop like the following:

start = entry()
for i in range(start.contents.state_len):
    print(start.contents.state[i])

Sources: https://docs.python.org/3/library/ctypes.html#type-conversions

Sign up to request clarification or add additional context in comments.

3 Comments

When I try this, I get the error: AttributeError: 'LP_Checkpoint' object has no attribute 'state' Your suggestion on how to structure things is a good one, though, thanks!
@KBriggs Right, I forgot that start is actually a pointer to a checkpoint. You must first access its contents using the .contents attribute. I'll update the answer accordingly
Oh, of course. I should have seen that ^_^. Thanks for your help!

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.