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:
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?
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?
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
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments