I need an array of pointers to functions with unspecified amount of arguments. The return value is defined and it's void
.
I understand, that if the functions are going to be stored in an array of pointers, for C to manage their calls, they need to have one specified signature.
It may seem like a contradiction, but it isn't. The array should contain arbitrary functions in terms of their arguments. Every single function has it's own signature that may differ from other functions in the array.
The common solution would be to use an void**
array of pointers to arguments, or just an void*
array of arguments themselves, and then typecast them.
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
void foo(void *args) {
uint32_t a;
uint16_t b;
uint16_t c;
memcpy(&a, args, sizeof(uint32_t));
ssize_t position = sizeof(uint32_t);
memcpy(&b, args+position, sizeof(uint16_t));
position += sizeof(uint16_t);
memcpy(&c, args+position, sizeof(uint16_t));
printf("a: %d\nb: %d\nc: %d", a, b, c);
}
void bar(void *args) {
/* ... */
};
int main() {
void *args = malloc(8);
uint32_t a = 12;
uint16_t b = 40;
uint16_t c = 8;
memcpy(args, &a, sizeof(uint32_t));
ssize_t position = sizeof(uint32_t);
memcpy(args+position, &b, sizeof(uint16_t));
position += sizeof(uint16_t);
memcpy(args+position, &c, sizeof(uint16_t));
position += sizeof(uint16_t);
void (*functions[16])(void *);
functions[0] = foo;
functions[1] = bar;
functions[0](args);
return 0;
}
Though it works, that approach is unsafe and leaves possibility for unspecified function input.
Is there a simpler or safer way to do that without leaving the functions caller behind the wheel?
There's a reason that a single void *
argument is the common way to do something like this. While it doesn't give you full control in terms of type checking, it's the best that can be done.
In your specific case, rather than creating a memory buffer with the parts manually copied in via memcpy
, you should make a struct that contains the function's arguments and pass that.
struct foo_args {
uint32_t a;
uint16_t b;
uint16_t c;
};
struct bar_args {
double x;
const char *y;
};
void foo(void *p) {
struct foo_args *args = p;
printf("a: %d\nb: %d\nc: %d", args->a, args->b, args->c);
}
void bar(void *p) {
struct bar_args *args = p;
printf("x: %f, y: %s\n", args->x, args->y);
};
int main() {
void (*functions[16])(void *);
functions[0] = foo;
functions[1] = bar;
struct foo_args f_args = { 12, 40, 8 };
functions[0](&f_args);
struct bar_args b_args = { 4.5, "test" };
functions[1](&b_args);
return 0;
}