In order to improve type safety in some C library code, I got the idea to use user-definable types in callback functions. So instead of carrying a void* around, the code uses a Usertype*. The library does only declare the type, but not define it, and uses this type as an opaque pointer. Instead of the regular scheme, that a library defines all used types, the parts which are used in callback functions are forward declared, and left to be defined by the user.
/*library code*/
struct UserDataForFooCallback; /* opaque user datatype */
typedef void CallbackFn(int i, struct UserDataForFooCallback* user);
void foo(CallbackFn* callback, struct UserDataForFooCallback* user)
{
callback(42, user);
}
/*application code*/
#include <stdio.h>
#include "foo.h"
struct UserDataForFooCallback
{
int a;
};
static void fooCallback(int i, struct UserDataForFooCallback* user)
{
printf(user->a == i ? "ok\n" : "fail\n");
}
int main()
{
struct UserDataForFooCallback cbd = {42};
foo(fooCallback, &cbd);
return 0;
}
Advantages:
- Type safe callbacks
- no
struct MyFoo* data=argpointer assignments in the callback code
Drawbacks:
- AFAIK there must not be more than one definition of a user defined datatype (or am I mixing this with the one definition rule of C++?), which makes them problematic if there are more than uses of the back-calling function (say
fooin the example is used by different program parts) - The need to define a new type for every callback/group of callbacks (maybe it’s not so important, since the many callback functions does use one already)
The main thing I want to know if this is really a good idea, or if thie is only a good-looking-but-Armageddon-like-impact idea.
If there are two libraries using your library, that both defined
UserDataForFooCallbackas a different structure, it is One Definition Rule violation. Just stick withvoid*.