Reputation: 5552
Let's consider this scenario of a C program:
RESPONSE_CALLBACK_T response_callback = &response_callback_function;
SendRequest(param1, param2, response_callback);
The SendRequest
function may post some data on a webserver or call some other program modules which are supposed to trigger a callback once they complete their job. Thus, when calling this function, we need to specify a pointer to our defined callback function.
Is there an elegant way of writing this code similar to a high-level OPP language that supports lambda expressions, e.g.:
SendRequest(param1, param2, function(int responseCode) { print(responseCode) });
How can I best simulate this behaviour?
Upvotes: 1
Views: 1103
Reputation: 29126
In standard C there is no way to provide function literals; function pointers must point to top-level functions. There's also no way to capture local variables that are not passed as arguments.
But, in order of increasing (alleged) elegance and decreasing protability (and probably also decreasng reliability):
In your example, you don't need the intermediate variable response_callback
. In C, typedef
s are just aliases to types and if a function's signature matches the signature of RESPONSE_CALLBACK
, you can use the function's name directly:
SendRequest(param1, param2, response_callback_function);
You don't need the &
operator for function pointers, either. I find that elegant enough by C's elegance standards.
Some compilers, e.g. gcc, implement nested functions, which allow you to define the function near where it's used:
if (print_flag) {
void func(int rc) { print(rc); }
SendRequest(param1, param2, func);
}
Nested functions in conjunction with statement expressions, which are also a non-standard extension supported by only some compilers, can be used to write a lambda macro. I don't find the macro shown on that site especially elegant, but if you have classes of callbacks, e.g. event handlers, you could simplify the macro (if you are willing to use the same hard-coded parameter names throughout):
#define handler(l_body) \
({ void l_anonymous(int rc) l_body l_anonymous; })
and call it like so:
SendRequest(param1, param2, handler({ print(rc); }));
(You could make the curly braces part of the macro, but the semicolon after the statement in the callback looks odd; I prefer the braces to be in client code.)
Note This seems to be a feature that happens to work rather than something that works by design. And you should not use any local variables of the enclosing function for callbacks that may be called when these variables' lifetime has ended. (It will compile, but cause run-time errors.) Proceed carefully.
Some compilers may have extensions for real lambdas or function literals, but I am not aware of any.
Upvotes: 3