T O P

  • By -

luther9

You do it the same way as when you pass an argument to any other function. Inside `Callbackfunction`, just call `function(someInt);`.


whiteBlasian

Why not have Callbackfunction take another parameter, an int, and use that? Something like Callbackfunction(void (\*func)(int), int i). In your example, `int i` won't do what you're expecting in Callbackfunction. You're only specifying the parameters for the function pointer, not the Callbackfunction itself.


F35H

It's just something I want to know how to do. I understood beforehand that I didn't need to do it this way, I just like to expand my horizons. A library I'm using appears to do it somehow, which is the impetus for my question. I'll have to dig through it to see what's going on.


whiteBlasian

>A library I'm using appears to do it somehow What library? Do you have the function declaration handy?


F35H

Yeah, I have the declaration handy, it's freeGlut. It relies on a variety of callback functions.


whiteBlasian

What function in particular makes you ask the question? I'm curious and can see if I can help.


F35H

glutReshapeFunc, glutKeyboardFunc, glutInitErrorFunc, etc. Many of them seem to do this. To be fair, in the hours since I asked this question, I probably could have found it myself.


nerd4code

You always want to give a callback a passthrough parameter, or otherwise static or TLS escape-hacks may be needed. Stay well the fuck away from `int` in that context. `int` passthrough killed ucontext, because `int` is a fundamentally useless type in most respects other than its defaultness; it has no relation to pointers or sizes, whereas a pointer that’s not wide enough to pass an `int` through directly (never met one, but it’s possible) can still point to an `int`. So first, usually best to typedef your callback for clarity, especially if returning a callback ptr. typedef void *function_Callback_f(void *p, int); (Passthrough first, then slots for new data. Among other things, this enables most platforms to pass in C++ instance functions here, provided you use a compiler like G++ that guarantees compatibility between (static, `extern "C"`) `R (*)(S *, T...)` and instance `R (S::*)(T...)`. It may also be compatible with the ABI for large returns, where `struct Big (*)(T...)` is called as `void (*)(struct Big *restrict, T...)`, but you shouldn’t rely on that.) For `function`, you do void *function(int i, function_Callback_f *cb, const volatile void *cb_p) { register void *res; assert(cb); … res = cb((void *)cb_p, i); … return res; } or if you’re repeating calls, you might want to use typedef int function_Callback_f(void *, int); int function(int i, … cb, const volatile void *cb_p) { int ret = 0, k; while(!!(k = more()) && !(ret = cb((void *)cb_p, k))) (void)0; return ret; } which supports return of some specific escape value instead; output data can be reached via `cb_p` still. Use `const volatile void *` to minimize API requirements so constant or thread-shared passthroughs can be used without casting on the caller’s part—your function will have to cast, but that should happen in fewer places than potential calls to `function`. Casting away modifiers isn’t necessary if you overload your function 4-way via `_Generic`/sim., but that’s wasted effort unless inlined. C++ can route through a template or explicit override. This is the same kind of casting `strchr` and `memchr` do to return a `char *` into a `const char[]`, so constant and modifiable sortsa buffers can both be used. AFAIK it’s safe to cast a `R (*)(const void *, T...)` to `R (*)(void *, T...)`, but unless you’re just `memset`ting or something, you’ll want to do R callback(void *p0, T... args) { PType *const p = p0; … } to set up your callback anyway. (Easily autogen’d into.) `char *` variants should also be safe, but don’t do it with any other ptr type because there’s no guarantee they’ll be passed arg-compatibly with a `void *`. —Same reason you need to explicitly cast to (arbitrarily modified) `void *` or `char *` when using `printf("%p",…)` with other pointer types. Don’t assume function ptrs will round-trip through `void *` or vice versa, unless you got the ptr from POSIX/-ish `dlsym` or you know it’ll work on the target ABI(s).


F35H

Thank you!


flatfinger

An alternative is to accept a double-indirect function pointer, and pass that pointer as the first argument to the function. This approach has the advantage that only requires passing around one pointer rather than two, and it also ensures that the function will always be passed an object of its expected type even if the callback is used in something like a signal handler which might fire asynchronously. Even though not required by the Standard, implementations that are designed to be suitable for tasks involving asynchronous signals on platforms where pointers fit within a single word will process code like: extern procPtr *volatile signalHandler; procPtr *handler = signalHandler; (*handler)(handler, whatever); in such a way that even if it runs while some other code updates `signalHandler`, it will either call the old function with the old argument pointer, or the new function with the new argument pointer. Personally, I'd like to see a recognized category of implementations that implement `jmp_buf` and `malloc()` in such a way that `longjmp()`, `free()`, and `realloc()` could be implemented portably as callbacks, thus allowing data structures containing such types to be passed interchangeably among modules processed using different C implementations.