We have given Cython code:
cdef extern from "C_File_A.h":
cdef struct C_Obj_A:
pass
cdef extern from "C_File_B.h":
cdef struct C_Obj_B:
pass
cdef class pC_Obj_A:
cdef const C_Obj_A * _c_self
cdef class pC_Obj_B:
cdef const C_Obj_B * _c_self
cdef class pC_Obj_C:
cdef const C_Obj_A * _c_a
cdef const C_Obj_B * _c_b
cdef class Obj_A_Wrap(pC_Obj_A):
def __init__(self, pC_Obj_C obj_c):
self._c_self = obj_c._c_a
cdef class Obj_B_Wrap(pC_Obj_B):
def __init__(self, pC_Obj_C obj_c):
self._c_self = obj_c._c_b
cdef class Stack:
cdef public pC_Obj_A obj_a
cdef public pC_Obj_B obj_b
def __init__(self, pC_Obj_C obj_c):
# Working
self.obj_a = Obj_A_Wrap(obj_c)
self.obj_b = Obj_B_Wrap(obj_c)
# Working
self.obj_a._c_self = obj_c._c_a
self.obj_b = Obj_B_Wrap(obj_c)
# Working
self.obj_a = Obj_A_Wrap(obj_c)
self.obj_b._c_self = obj_c._c_b
# Not working
self.obj_a._c_self = obj_c._c_a
self.obj_b._c_self = obj_c._c_b
I need a python object Stack
with attrubutes accessible from Python, so I have added to Stack class cdef public pC_Obj_A obj_a
and cdef public pC_Obj_B obj_b
.These objects are wrappers to the C struct pointers.
When I initialize these objects with intermediary wrappers i.e. Obj_A_Wrap
everything is fine.
When I initialize one of these objects directly i.e. self.obj_a._c_self = obj_c._c_a
also everything is fine.
When both obj_a
and obj_b
are initialized directly (# Not Working
part of code) I have got strange behaviour of my C library that inlcude C_File_A
and C_File_B
and respectively the C structs definitions. The behaviour is similar to memory corruption, or overwriting some parts of the memory that should not be.
I have no idea why the direct initialization causes this strange behaviour. Maybe you know?
I have found the solution of my problem. When I was trying to solve this problem I have printed only _c_self
attribute of the given object to check that the pointer was properly assigned and it was but when I printed entire object it turned out that python object is None
instead of proper object declared as attribute.
print(self.obj_a, self.obj_b) # 66f000c0 66f000c0
print(f'{<int>self.obj_a._c_self:x} {<int>self.obj_b._c_self:x}') # None None
The solution is to add Create
function to cdef class:
cdef class pC_Obj_A:
cdef const C_Obj_A * _c_self
@staticmethod
cdef Create(C_Obj_A * ptr):
cdef pC_Obj_A result = pC_Obj_A()
result._c_self = ptr
return result
And use it like this:
cdef class Stack:
cdef public pC_Obj_A obj_a
cdef public pC_Obj_B obj_b
def __init__(self, pC_Obj_C obj_c):
self.obj_a = pC_Obj_A.Create(obj_c._c_a)
self.obj_b = pC_Obj_B.Create(obj_c._c_b)
Then printout is:
print(self.obj_a, self.obj_b) # <pC_Obj_A object at 0x029FF610> <pC_Obj_B object at 0x029FF620>
print(f'{<int>self.obj_a._c_self:x} {<int>self.obj_b._c_self:x}') # 2134b9c 2134c08
And everything works great!