STRUCT_ARRAY in your code should be a pointer to a pointer array, not a pointer to an element in the array, as you are appending STRUCT_2 pointers to the array.
In C, STRUCT_ARRAY can be defined as *STRUCT_2[length], aka an array of STRUCT_2 pointers
import ctypes
from random import randint
class STRUCT_2(ctypes.Structure):
#_pack_=2
_fields_ = [('field_1', ctypes.c_short),
('field_2', ctypes.c_short),
('field_3', ctypes.c_short),
('field_4', ctypes.c_short),
('field_5', ctypes.c_short),
('field_6', ctypes.c_short),
('field_7', ctypes.c_short),
('field_8', ctypes.c_short)]
class STRUCT_1(ctypes.Structure):
#_pack_=2
_fields_ = [('elements', ctypes.c_short),
#an array of pointers
('STRUCT_ARRAY', ctypes.POINTER(ctypes.POINTER(STRUCT_2)))]
def __init__(self,num_of_structs):
elems = (ctypes.POINTER(STRUCT_2) * num_of_structs)()
self.STRUCT_ARRAY = ctypes.cast(elems,ctypes.POINTER(ctypes.POINTER(STRUCT_2)))
self.elements = num_of_structs
for num in range(0,num_of_structs):
self.STRUCT_ARRAY[num].field_1 = 1
self.STRUCT_ARRAY[num].field_2 = 2
self.STRUCT_ARRAY[num].field_3 = 3
for num in range(0,100):
test = STRUCT_1(num)
print("%i done" % num)
If instead what you want is an array of structs, use the following code:
import ctypes
from random import randint
class STRUCT_2(ctypes.Structure):
#_pack_=2
_fields_ = [('field_1', ctypes.c_short),
('field_2', ctypes.c_short),
('field_3', ctypes.c_short),
('field_4', ctypes.c_short),
('field_5', ctypes.c_short),
('field_6', ctypes.c_short),
('field_7', ctypes.c_short),
('field_8', ctypes.c_short)]
class STRUCT_1(ctypes.Structure):
#_pack_=2
_fields_ = [('elements', ctypes.c_short),
#an array of structs
('STRUCT_ARRAY', ctypes.POINTER(STRUCT_2))]
def __init__(self,num_of_structs):
elems = (STRUCT_2 * num_of_structs)()
self.STRUCT_ARRAY = ctypes.cast(elems,ctypes.POINTER(STRUCT_2))
self.elements = num_of_structs
for num in range(0,num_of_structs):
self.STRUCT_ARRAY[num].field_1 = 1
self.STRUCT_ARRAY[num].field_2 = 2
self.STRUCT_ARRAY[num].field_3 = 3
self.STRUCT_ARRAY[num].field_4 = 4
for num in range(0,100):
test = STRUCT_1(num)
print("%i done" % num)
Answer from simonzack on Stack OverflowD Hess put me in the right direction; The solution was:
GroupArray = POINTER(Group * count)
group_array = GroupArray.from_address(addressof(myGroups))
for x in range(0,count):
print "~~~~~~~~~~" + group_array.contents[x].groupname
First create a new type which is an array of Group:
GroupArray = Group * count
Then create an instance of a GroupArray this way:
group_array = GroupArray.from_address(myGroups.value)
Then your loop would work like this:
for x in range(0,count):
print "~~~~~~~~~~" + group_array[x].groupname
you are mixing up between creating a struct, creating an array of struct, and creating a pointer to an array of struct, those are 3 different operations, i have commented the code for clarity.
import numpy as np
from ctypes import cdll
from ctypes import *
class complex(Structure): # struct with two floats
_fields_ = (('Re', c_float),
('Im', c_float))
def __init__(self, I_val, Q_val):
self.Re = I_val
self.Im = Q_val
def __repr__(self):
return f'Complex({self.Re}, {self.Im})'
I = [2,2,3,4]
Q = [5,6,7,8]
lenIQ = len(I)
my_array_type = complex*lenIQ # create the type of array (complex[])
my_array = my_array_type() # create the array (complex my_array[4])
for i in range(len(I)):
my_array[i] = complex(I[i],Q[i]) # fill each individual object in the array
# next line is equivalent to "complex* pointer_to_array = (complex*)(my_array);"
pointer_to_array = cast(my_array, POINTER(complex)) # create the pointer to the first element of the array (complex*)
print(my_array) # prints type of my_array
print(my_array[0]) # equivalent to c's my_array[0]
print(pointer_to_array[0]) # equivalent to c's pointer_to_array[0]
<__main__.complex_Array_4 object at 0x000002195A9B8C40>
Complex(2.0, 5.0)
Complex(2.0, 5.0)
now for calling
cgmap = cdll.LoadLibrary('./test.dll')
test = cgmap.test
test.argtypes = (c_int, POINTER(complex))
test.restype = None
test(c_int(lenIQ), pointer_to_array)
Make sure your types match. The structure contains c_float not POINTER(c_float) to match the C definition. The .argtypes are c_int and POINTER(Complex).
ctypes can initialize the structure and arrays without a lot of extra work:
test.c
#include <stdio.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
typedef struct { float Re; float Im; } complex;
API void test(int N, complex *v) {
int k;
for(k = 0; k < N; ++k) {
v[k].Re = v[k].Re + 1;
v[k].Im = v[k].Im + 1;
printf("%d %f %f\n", k, v[k].Re, v[k].Im);
}
}
test.py
import ctypes as ct
class Complex(ct.Structure):
_fields_ = (('Re', ct.c_float), # not POINTER(c_float)
('Im', ct.c_float))
def __repr__(self):
return f'Complex({self.Re:g}{self.Im:+g}j)'
@staticmethod
def array(reals, imags):
'''Helper method to create Complex arrays.
'''
return (Complex * len(reals))(*zip(reals, imags))
I = [2,2,3,4]
Q = [5,6,7,8]
arr = Complex.array(I, Q)
print(list(arr)) # easy way to display the contents when __repr__ is defined.
dll = ct.CDLL('./test')
dll.test.argtypes = ct.c_int, ct.POINTER(Complex)
dll.test.restype = None
dll.test(len(arr), arr)
Output:
[Complex(2+5j), Complex(2+6j), Complex(3+7j), Complex(4+8j)]
0 3.000000 6.000000
1 3.000000 7.000000
2 4.000000 8.000000
3 5.000000 9.000000