Having looked at code for interfacing Eiffel to C and creating callbacks from C to Eiffel, I frequently found that things were not done properly, resulting in potential memory corruption or crashes.
First, I like to point out the CECIL documentation which contains everything you need to know about interfacing C with Eiffel. It might be overwhelming so below is a simplified tutorial.
Typing
At the C level, Eiffel objects are known under 2 possible types:EIF_REFERENCE: a direct reference to an Eiffel objectEIF_OBJECT: an indirect (or protected) reference to an Eiffel object
The reason for having 2 types lies in the garbage collector (GC) which moves objects around at runtime. As a consequence, a direct reference is not always valid, meaning that if you use an EIF_REFERENCE variable, then it might points to the previous location of the object. This is why we have EIF_OBJECT, those variable are automatically updated by the GC. To access the Eiffel objects, one has to use the eif_access function.
Callbacks
The corresponding C signature of an Eiffel routine is the same as the Eiffel routine except that there is an extra first argument for the target object of the call. In other words, the Eiffel codeThe types used for the declaration of the C routine are simply the Eiffel types prefixed by `EIF_' for the basic types (INTEGER_XX, NATURAL_XX, POINTER, ....) and EIF_REFERENCE for all the other types. Therefore the following Eiffel routine:
Passing an Eiffel routine to a C external
Instead of using the CECIL API for getting the address of an Eiffel routine, I'm using an alternative which is much lighter and simpler to use in my opinion. This is the technique used in all the Eiffel Software libraries where a simple callback is needed.Basically if you want to pass the function pointer of the Eiffel routine my_routine above, you simply have to wrap the following C routine:
external
"C inline use %"my_c_header.h%""
alias
"set_callback_function (($a_routine);"
end
set_callback_function C routine sets a C variable callback_function.
Passing the object target of the call to C
Now, we need to store the Eiffel objects on the C side. As we have seen above, we need to provide the C side with a protected reference to the Eiffel object, otherwise the reference might not be valid after a GC cycle. So on the C side, we need another C variableeiffel_object which is of type EIF_OBJECT. To pass this object from the Eiffel side to the C side you can simply do the following: external
"C inline use %"my_c_header.h%""
alias
"set_eiffel_object (eif_protect($a));"
end
set_eiffel_object ($my_object)


