nullplan wrote:For example, you cannot implicitly convert a void** to int**.
Okay, that's new information to me, but I can see why you wouldn't want that after giving it some thought. void* has special significance that doesn't generalize to types made out of void*.
The same is true for your function pointers. In theory, all pointer types could have different representations
Right, this is the undefined behaviour I'm trying to avoid. This would be a reasonable enough assumption for me to make because the code is pretty heavily tied to a particular platform, as a hobby project I'm interested in making it as portable as possible.
Seeing as they're callbacks, I would probably attempt to figure out the signature of the callback functions and declare the callback pointers of that type.
The type of the callback function is
(or a pointer to a union over all the types used in the actual codebase). The callback function always takes a pointer to a struct that is used to store state across invocations of the callback, each callback has its own struct for its own needs.
The conclusion that I came up with while I was waiting for this thread to be accepted was that all the callback functions should look something like this,
Code: Select all
void callback(void* param_) {
struct particular_callback_state const * param = param_;
/* ... */
}
I understand now why the cast has to be explicit. When the original function is called, the caller is providing a
parameter, but the callee of will go looking for a
Code: Select all
struct particular_callback_state *
parameter. The series of casts is allowed, but the language doesn't guarantee that the casts will be compiled to no-ops so it has to be explicit.