ctypes pointer to structure memory swap

W

Wanderer

I'm observing some strange behavior with ctypes. I created this test
code to try to figure out what I'm doing wrong creating pointers to
structures.

from ctypes import *

class QCamSettingId(Structure):
""" QCam_settings_id
"""
_fields_ = [("f1", c_ulong),
("f2", c_ushort),
("f3", c_ushort),
("f4", c_ubyte * 8)]


class QCamSettingsEx(Structure):
""" QCam_SettingsEx
"""
_fields_ = [("size", c_ulong), # Filled by
the init routine
("pSettingsID", POINTER(QCamSettingId)), # pointer
to the camera settings ID
("private_data", c_void_p )] # Pointer
to a camera settings array

class QMemDriver():
""" The wrapper of QCamDriver
"""
def __init__(self):

self.QSetID = QCamSettingId()
self.QSetID_p = pointer(self.QSetID)
self.QSettings = QCamSettingsEx()
self.QSettings.pSettingsID = self.QSetID_p
self.QSettings_p = pointer(self.QSettings)

def Test(self):
"""
Test the QCamSettinsEx object
"""
print self.QSettings.pSettingsID
print self.QSettings.pSettingsID[0]
print self.QSettings.pSettingsID
print self.QSettings.pSettingsID[0]
print "pSettingsID is at", self.QSettings.pSettingsID
print "pSettingsID[0] is at", self.QSettings.pSettingsID[0]
print "pSettingsID is at", self.QSettings.pSettingsID
print "pSettingsID[0] is at", self.QSettings.pSettingsID[0]


The results I get are.
<QMEMTest.LP_QCamSettingId object at 0x011902B0>
<QMEMTest.QCamSettingId object at 0x01426850>
<QMEMTest.LP_QCamSettingId object at 0x011902B0>
<QMEMTest.QCamSettingId object at 0x01426850>
pSettingsID is at <QMEMTest.LP_QCamSettingId object at 0x011902B0>
pSettingsID[0] is at <QMEMTest.QCamSettingId object at 0x01426850>
<QMEMTest.LP_QCamSettingId object at 0x01426990>
<QMEMTest.QCamSettingId object at 0x014269E0>
<QMEMTest.LP_QCamSettingId object at 0x014269E0>
<QMEMTest.QCamSettingId object at 0x01426990>
pSettingsID is at <QMEMTest.LP_QCamSettingId object at 0x01426990>
pSettingsID[0] is at <QMEMTest.QCamSettingId object at 0x014269E0>
pSettingsID is at <QMEMTest.LP_QCamSettingId object at 0x014269E0>
pSettingsID[0] is at <QMEMTest.QCamSettingId object at 0x01426990>

Sometimes the pointer and the object swap location and sometimes they
don't.
 
N

Nobody

I'm observing some strange behavior with ctypes. I created this test
code to try to figure out what I'm doing wrong creating pointers to
structures.

What makes you think that you're doing anything wrong.

Note that the hex number shown when printing a ctypes object is the
object's ID (as per the id() function). This is typically the address of
the Python object. It is not the address of the structured data nor (in
the case of a ctypes pointer) the value of the pointer.

If you want to see the actual value of a ctypes pointer, cast it to
c_void_p then examine the .value field, e.g.:

p = pointer(x)
print hex(cast(p, c_void_p).value)
 
W

Wanderer

What makes you think that you're doing anything wrong.

Note that the hex number shown when printing a ctypes object is the
object's ID (as per the id() function). This is typically the address of
the Python object. It is not the address of the structured data nor (in
the case of a ctypes pointer) the value of the pointer.

If you want to see the actual value of a ctypes pointer, cast it to
c_void_p then examine the .value field, e.g.:

        p = pointer(x)
        print hex(cast(p, c_void_p).value)

In the real program the pointer to the structure is passed to the DLL.
The DLL has functions CreateCameraSettingsStruct and
ReleaseCameraSettingsStruct. Once I call CreateCameraSettingStruct, I
can't delete the pointer without crashing Python. Calling
ReleaseCameraSettingStruct doesn't help. The result is the program
crashes on exit during the class destruction. I was trying to figure
out why ReleaseCameraSettingStruct doesn't release the pointer so
Python can close the program. I was checking to see what happened
before and after ReleaseCameraSettingStruct and saw this. But it
happens even if I don't run ReleaseCameraSettingStruct.

Thanks for the reply, but I'm still not sure I understand. Why should
Object1 be at address1 and Object2 be at address2 and the next moment
Object2 is at address1 and Object1 is at address2? I'll try casting
them to see what the value is before and after calling
ReleaseCameraSettingStruct.
 
N

Nobody

Thanks for the reply, but I'm still not sure I understand. Why should
Object1 be at address1 and Object2 be at address2 and the next moment
Object2 is at address1 and Object1 is at address2? I'll try casting
them to see what the value is before and after calling
ReleaseCameraSettingStruct.

QCamSettingsEx is a ctypes Struct object. The pSettingsID "field" is a
ctypes field, not a Python field. It will contain a "bare" pointer to the
C-struct for the QCamSettingId object.

The point of a ctypes Struct is to store data in a format usable by C
code, i.e. the memory layout will match that of a C struct. In particular,
pointers within that struct will be pointers to C-compatible data (e.g. C
structs), not pointers to Python objects. If you access the fields from
Python, ctypes will generate Python objects on-the-fly from the raw data.

Whenever you read the pSettingsID field, ctypes will generate a ctypes
pointer object (LP_QCamSettingId?) which wraps the underlying C pointer.
If you dereference that, ctypes will generate a Python QCamSettingId
object which wraps the C struct.

As you aren't storing the references, as soon as the print statement
completes, the reference count will drop to zero and the object will be
deallocated. The next time you reference pSettingsID or pSettingsID[0], a
new object will be constructed. The addresses (and thus IDs) of the Python
objects are entirely arbitrary.
 
W

Wanderer

Thanks for the reply, but I'm still not sure I understand. Why should
Object1 be at address1 and Object2 be at address2 and the next moment
Object2 is at address1 and Object1 is at address2? I'll try casting
them to see what the value is before and after calling
ReleaseCameraSettingStruct.

QCamSettingsEx is a ctypes Struct object. The pSettingsID "field" is a
ctypes field, not a Python field. It will contain a "bare" pointer to the
C-struct for the QCamSettingId object.

The point of a ctypes Struct is to store data in a format usable by C
code, i.e. the memory layout will match that of a C struct. In particular,
pointers within that struct will be pointers to C-compatible data (e.g. C
structs), not pointers to Python objects. If you access the fields from
Python, ctypes will generate Python objects on-the-fly from the raw data.

Whenever you read the pSettingsID field, ctypes will generate a ctypes
pointer object (LP_QCamSettingId?) which wraps the underlying C pointer.
If you dereference that, ctypes will generate a Python QCamSettingId
object which wraps the C struct.

As you aren't storing the references, as soon as the print statement
completes, the reference count will drop to zero and the object will be
deallocated. The next time you reference pSettingsID or pSettingsID[0], a
new object will be constructed. The addresses (and thus IDs) of the Python
objects are entirely arbitrary.

Great explanation. Now I understand. Thanks
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top