C: Passing array to pointer function -


i'm not sure if question has asked before, couldn't find similar topics.

i'm struggeling following piece of code. idea extend r time later on without writing lots of if-else statements. functions (func1, func2...) either take 0 or 1 arguments.

void func1() {     puts("func1"); }  void func2(char *arg){     puts("func2");     printf("with arg %s\n", arg); }  struct fcall {     char name[16];     void (*pfunc)(); };  int main() {     const struct fcall r[] = {         {"f1", func1},         {"f2", func2}     };     char param[] = "someval";      size_t nfunc = rsize(r); /* array size */     for(;nfunc-->0;) {         r[nfunc].pfunc(param);     }     return 0; } 

the code above assumes functions take string argument, not case. prototype pointer function declared without datatype prevent incompatible pointer type warning.

passing arguments functions not take parameters results in too few arguments. in case compiler doesn't 'see' ahead, let me believe no optimization done exclude these unused addresses being pushed onto stack. (i haven't looked @ actual assemble code).

it feels wrong someway , that's recipe buffer overflows or undefined behaviour. better call functions without parameters separately? if so, how damage do?

the way typedef function 1 argument, compiler verify if pass correct number of arguments , not pass absolutely incompatible (e.g. struct value). , when initialize array, use typedef cast function types.

void func1(void) { ... }  void func2(char *arg) { ... }  void func3(int arg) { ... }  typedef uintptr_t param_t;     typedef void (*func_t)(param_t);  struct fcall {     char name[16];     func_t pfunc; };  const struct fcall r[] = {     {"f1", (func_t) func1},     {"f2", (func_t) func2}     {"f3", (func_t) func3} };  ...  r[0].pfunc((param_t) "foo"); r[1].pfunc((param_t) "bar"); r[2].pfunc((param_t) 1000); 

here param_t defined uintpr_t. integer type big enough store pointer value. details see here: what uintptr_t data type. caveat calling conventions param_t should compatible function arguments use. true integer , pointer types. following sample going work, type conversions compatible each other in terms of calling conventions:

// no problem here. void ptr_func(struct my_struct *ptr) {     ... } ... struct my_struct struct_x; ((func_t) &ptr_func)((param_t) &struct_x); 

but if going pass float or double argument, might not work expected.

// there might problem here. depending on calling // conventions value might contain complete garbage, // might taken floating point register // not set on call site. void float_func(float value) {     ... } ... float x = 1.0; ((func_t) &float_func)((param_t) x); 

in case might need define function this:

// problem fixed, partially. instead of garbage // there might rounding error after conversions. void float_func(param_t param) {     float value = (float) param;     ... } ... float x = 1.234; ((func_t) &float_func)((param_t) x); 

the float first being converted integer type , back. result value might rounded. obvious solution take address of x , pass modified function float_func2(float *value_ptr). function dereference pointer argument , actual float value.

but, of course, being hardcore c-programmers not want obvious, going resort ugly trickery.

// problem fixed true c-programmer way. void float_func(param_t param) {     float value = *((float *) &param);     ... } ... float x = 1.234; ((func_t) &float_func)(*((param_t *) &x)); 

the difference of sample compared passing pointer float, on architecture (like x86-64) parameters passed on registers rather on stack, smart enough compiler can make float_func job using registers only, without need load parameter memory.


Comments

Popular posts from this blog

javascript - AngularJS custom datepicker directive -

javascript - jQuery date picker - Disable dates after the selection from the first date picker -