Wednesday, 24 April 2013

Function pointer type compatibility

I've been wondering how function pointers get passed around inside the GObject framework. Some example code seems to play fast and loose with function pointer types, relying on the fact that C's Undefined Behaviour can also include doing what one hopes. After some source-diving I finally found how GLib calls the callback. It does it through a function pointer of this type in one example:
typedef void (*GMarshalFunc_VOID__UINT_POINTER) (gpointer instance, guint arg_0, gpointer arg_1, gpointer data);
That's for a signal handler whose signature is void ()(gpointer instance, guint x, gpointer userdata). Because GtkCellRendererText * and void * are not compatible types, it's actually wrong (it invokes undefined behaviour) to simply copy the signal handler signatures from the GTK+ documentation! For this example, the correct function declaration would have to be:
void user_function(gpointer renderer, gpointer path, gpointer new_text, gpointer user_data);
I'm not sure if I want to be that pure. Too much boilerplate type conversion code. Maybe the reasonable compromise is to continue using pointers to specific types, but to make sure that at least the number of arguments matches what the marshaller functions demand. I think it's far more likely that a C implementation will be sensitive to a mismatched number of arguments (consider how cdecl vs pascal calling convention specifiers in some compilers determine a function's activation record) than that void * will have a different representation than GtkCellRendererText *.