Rahul
Rahul

Reputation: 1021

How do I construct an array of ctype structures?

>>> from ctypes import *
>>> class A(Structure):
...  _fields_ = [('a', c_int), ('b', c_int)]
...  def __init__(self, x):
...   self.a = x + 1
...   self.b = x + 2
... 
>>> a = A(1)
>>> a.a
2
>>> a.b
3
>>> b = (A * 2)(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: expected A instance, got int

I am trying to construct an array of C structures in python and want the constructor to be called for each element in the array. How can I accomplish this?

Upvotes: 5

Views: 2380

Answers (1)

Alex Huszagh
Alex Huszagh

Reputation: 14614

The error explains exactly the problem, but in a slightly convoluted manner:

The correct way to initialize such an array is as follows:

structs = [A(1, 2), A(1, 2)]
array = (A * 2)(*structs)

Or, if you can define them all during the array constructor, as follows:

array = (A * 2)(A(1, 2), A(1, 2))

Now, why does this work and your solution not? Since I am passing an instance of A for each argument to the constructor of A * 2, which is an array of A. The array requires an instance of A for each argument passed, which is precisely the error message. It does not expect to convert arguments into A, it expects an instance of A itself.

The step-by-step way is as follows:

from ctypes import *
class A(Structure):
    _fields_ = [('a', c_int), ('b', c_int)]

# this create a class which expects 2 A instances
a_array_factory = A * 2
# our first A instance
struct_1 = A(1, 2)
# our second A instance
struct_2 = A(2, 3)
# initialize our array
array = a_array_factory(struct_1, struct_2)

EDIT:

Since a structure does not have a native Python type, there is no solution, to my knowledge, without creating intermediary structs. According to the Python documentation, the only native types with C primitives are the following:

ctypes type     C type                                      Python type
c_bool          _Bool                                       bool (1)
c_char          char                                        1-character string
c_wchar         wchar_t                                     1-character unicode string
c_byte          char                                        int/long
c_ubyte         unsigned char                               int/long
c_short         short                                       int/long
c_ushort        unsigned short                              int/long
c_int           int                                         int/long
c_uint          unsigned int                                int/long
c_long          long                                        int/long
c_ulong         unsigned long                               int/long
c_longlong      __int64 or long long                        int/long
c_ulonglong     unsigned __int64 or unsigned long long      int/long
c_float         float                                       float
c_double        double                                      float
c_longdouble    long double                                 float
c_char_p        char * (NUL terminated)                     string or None
c_wchar_p       wchar_t * (NUL terminated)                  unicode or None
c_void_p        void *                                      int/long or Nonee or None

Upvotes: 8

Related Questions