I noticed that I cannot default initialize an object of ctypes.Structure derived class when it has bit fields in it, but I can default initialize an array of such objects.
Let's say we define such a class:
class What(ctypes.Structure):
_fields_ = [('x', ctypes.c_float), ('y', ctypes.c_short, 2)]
def __init__(self, x=None, y=None):
if not x:
x = ctypes.c_float()
if not y:
y = ctypes.c_short()
super(What, self).__init__(x, y)
Now this code executes smoothly and to my understanding, it makes use of the default constructor defined above.
what_arr = What * 4
w_arr = what_arr()
An array of zero-filled structs is returned. However, when I try to initialize just one object, I get an 'access violation reading location' error and the program crashes.
w = What()
It would be great if someone explained what is going under the hood and what is the reason for this behavior.
A couple more details:
I need to have
x = ctypes.c_float()
y = ctypes.c_short()
instead of directly passing 0s to initialization, because normally fields of the structure contain other structures and I want to use their default constructors here too (so that everything is recursively initialized with 0s).
I believe that this may be useful for people who want to test some wrapped package with dummy values first.
The base class doesn't know what x
and y
are. If I understand the OP correctly the default behavior of ctypes.Structure
is all that is needed. I added a __repr__
function to more easily see what is happening:
class What(ctypes.Structure):
_fields_ = [('x', ctypes.c_float), ('y', ctypes.c_short, 2)]
def __repr__(self):
return f'What(x={self.x},y={self.y})'
Testing...
>>> w = What()
>>> w
What(x=0.0,y=0)
>>> w = What(1.5)
>>> w
What(x=1.5,y=0)
>>> w = What(1.5,2)
>>> w
What(x=1.5,y=-2)
>>> wa = (What*4)()
>>> list(wa)
[What(x=0.0,y=0), What(x=0.0,y=0), What(x=0.0,y=0), What(x=0.0,y=0)]
Note also that ctypes structures are zero-initialized by default, so you don't need any magic here either even for nested structures:
import ctypes
class Inner(ctypes.Structure):
_fields_ = [('a',ctypes.c_int),('b',ctypes.c_int)]
def __repr__(self):
return f'Inner(a={self.a},b={self.b})'
class What(ctypes.Structure):
_fields_ = [('x', Inner), ('y', ctypes.c_short, 2)]
def __repr__(self):
return f'What(x={self.x},y={self.y})'
Testing...
>>> w = What()
>>> w
What(x=Inner(a=0,b=0),y=0)
>>> wa = (What*4)()
>>> list(wa)
[What(x=Inner(a=0,b=0),y=0), What(x=Inner(a=0,b=0),y=0), What(x=Inner(a=0,b=0),y=0), What(x=Inner(a=0,b=0),y=0)]