I ran into something very strange using Python and ctypes. I'm using Python 3.4.3. First, some background into the project:
I have compiled a custom dll from C code. I'm using ctypes to interface with the dll. The C library is interfacing with some custom hardware. Sometimes the hardware generates an interrupt and passes it along to the C library on the computer. In the C API, there is a function with the prototype void register_callback(int addr, void (*callback)(void)). I have an array of callback function pointers, which are initialized to NULL. When this function is called, the callback function pointer at index addr is set to callback, like this: callbacks[addr] = callback;.
When the user programs in Python, they instantiate objects from classes that model different hardware parts (such as a button or an RGB LED). They can then write a custom callback function and call button.register_callback(func) (assuming they have a Button object named button, of course), which calls the register_callback function in the C library. Now, when the button is pressed and the interrupt is generated, the C library will call the appropriate callback function (i.e. callbacks[addr]();).
Now, the weirdness:
In Python, my first attempt at the register_callback method in Python looked like this:
class Obj:
def __init__(self, name):
# Initialize stuff
def register_callback(self, func):
CB_T = ctypes.CFUNCTYPE(None)
cb_ptr = CB_T(func)
host_api.register_callback(self.addr, cb_ptr) # host_api is the loaded dll
And in main:
def cb1():
print("cb1")
def cb2():
print("cb2")
def main(argv):
# Initialization stuff
# Now create the objects and register the callbacks:
obj = Obj_module.Obj()
obj2 = Obj_module.Obj()
obj.register_callback(cb1)
obj2.register_callback(cb2)
while True:
pass
When I ran this, only "cb2" was being printed, regardless of which button I was pressing. The REALLY weird thing is that when I switched the order in which I registered the callbacks :
obj2.register_callback(cb2)
obj.register_callback(cb1)
only "cb1" was being printed, regardless of the button I pressed! In the C library, I verified (by printf) that different callback function pointers were being set and called, depending on the button, but that the same function pointer was being passed to the C register_callback function.
I was able to fix the problem by adding a line to the register_callback method:
def register_callback(self, func):
CB_T = ctypes.CFUNCTYPE(None)
cb_ptr = CB_T(func)
(ctypes.cast(cb_ptr, ctypes.POINTER(ctypes.c_int)))
host_api.register_callback(self.addr, cb_ptr)
Apparently, converting cb_ptr to a ctypes POINTER fixed the problem - different function pointers were being passed in, and I successfully saw "cb1" or "cb2" printed, depending on the button that I pressed.
My question is, WHY? Why was the same function pointer being passed in the original code, why was it changing depending on the order that I registered the callbacks, and why does converting cb_ptr to a ctypes POINTER ensure that the function pointers are different?
I'm kind of a beginner at Python, but I'm much more experienced at C. Thanks in advance for your responses.