Is there a way to build a wrapper function in C as follows:
void wrapper(void *func) {
// Set up
func([same arguments as func was passed in with]);
// Clean up
}
void foo(int x, int y);
void bar(char *z);
wrapper(foo(1, 2));
wrapper(bar("Hello"));
It seems as though you have to either pass in the arugments within wrapper
or only support one type of method header for func
. I've been writing a lot of Javascript... and of course this is possible in JS.
That's the best I can think of with variadic function wwrappers:
#include <stdio.h>
#include <stdarg.h>
void wrapper(void (*func)(va_list), ...) {
va_list args;
va_start(args, func);
func(args);
va_end(args);
}
void foo(int x, int y)
{
printf("foo(%d,%d)\n", x, y);
}
void vfoo(va_list args)
{
foo(va_arg(args, int), va_arg(args, int));
}
void bar(char *z)
{
printf("bar(%s)\n", z);
}
void vbar(va_list args)
{
bar(va_arg(args, char*));
}
int main()
{
wrapper(vfoo, 1, 2);
wrapper(vbar, "Hello, World!");
return 0;
}
Live example on Coliru.
Have you considered (ab)using the preprocessor?
#include <stdio.h>
#define wrapper(f) /* Set up */\
f; \
/* Clean up */
void foo(int x, int y) {
printf("x: %d; y: %d\n", x, y);
}
void bar(char *str) {
printf("str: %s\n", str);
}
int main(void) {
wrapper(foo(42, 11));
wrapper(bar("hello world"));
}
To elaborate upon why I added the possibility of an ab- prefix to (ab)use, I wouldn't hesitate to use whatever is the most expressive solution to a problem, regardless of the attitude held by the general populus. However, I recognise that sometimes we have no control over the restrictions we are bound by, and policies are often put in place to heavily restrict the use of macros. Unfortunately, those bound by such silly policies won't find this post too helpful.
In a comment above I suggested that "if you want a feature from Javascript you should probably write your code in Javascript...".
Upon pondering about this overnight, I came to the conclusion that features similar to those you ask are actually doable and would be quite nice in C... so I admit, I was wrong.
The following is an example of mimicking how Javascript treats functions.
#include <stdio.h>
struct argument;
typedef struct argument argument;
typedef void function(argument *);
struct argument {
function *function;
/* for foo() */
int x;
int y;
/* for bar() */
char *str;
};
void wrapper(argument *a) {
// set up
a->function(a);
// clean up
}
void foo(argument *a) {
printf("x: %d; y: %d\n", a->x, a->y);
}
void bar(argument *a) {
printf("str: %s\n", a->str);
}
#define foo(...) wrapper(&(argument){ .function = foo, __VA_ARGS__ })
#define bar(...) wrapper(&(argument){ .function = bar, .str = "", __VA_ARGS__ })
int main(void) {
foo(.x = 42, .y = 11);
bar(.str = "hello world");
}
There are actually some really nice features coming from this style of wrapper:
printf
and scanf
to cause subtle yet devastating bugs by passing the wrong types and/or values to those functions. This leads on to my next point:foo
and bar
macros. As an example in the code above, the default value for the argument named str
is set to ""
(an empty string) for bar
.wrapper
, you can mimic partial function application (or binding properties to functions, much like you'd see in Javascript). Additionally, with a little bit of effort, mimicking continuation passing style might be possible by turning wrapper
into a trampoline-style function and modifying the return value? I'll ponder more on this and provide an update tomorrow.There are some minor draw-backs, the most significant being that neither foo
nor bar
can be passed, unapplied, to another function as an argument. This would be rare for these functions specifically, as they differ greatly in signature, but for functions that are identical or even similar in signature I can understand one might want to pass them as callbacks or what-not.
The solution to that problem is to rename the macros to default_foo
and default_bar
or something like that...
Finally, thanks for asking such a thought-provoking question... I hope reading my answer has been as interesting for you as thinking about (and writing) it was for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With