0

I have a set of functions to be called e.g.:

void void_func();                   /* id = 0 */
void void_func1(int);               /* id = 1 */
void void_func2(int, char *);       /* id = 2 */
void void_func3(short int);         /* id = 3 */

int int_func();                     /* id = 4 */            
int int_func1(int);                 /* id = 5 */
int int_func2(float);               /* id = 6 */
int int_func3(int, int *);          /* id = 7 */

char *char_func();                  /* id = 8 */
char *char_func1(int);              /* id = 9 */
char *char_func2(int, int);         /* id = 10*/

void enum_func(enum_t);             /* id = 11*/
enum_t enum_func1(int *, int);      /* id = 12*/
enum_t enum_func2();                /* id = 13*/

I have defined the following function pointers and parameters for calling any of the above functions:

typedef void * (*funcptr)();
typedef void * (*funcptr1)(void *);
typedef void * (*funcptr2)(void *, void *);

void * parameter1;
void * parameter2;
void * return_param;

I have defined a custom struct for calling all the functions:

typedef struct funcid {
    int id;
    funcptr f0;
    funcptr1 f1;
    funcptr2 f2;
    void * param1;
    void * param2;
    void * ret_param;
} func_id;

I have initialized the struct as below based on id (At any time only one of the above functions is called):

func_id func_str[] = {
/*  { id,       f0      ,       f1      ,       f2      ,           param1          ,       param2          ,           ret_param       } ,*/
    { 0 , &void_func    ,   NULL        ,   NULL        , (void *)parameter1        , (void *)parameter2    , (void *)return_param      } ,
    { 1 ,   NULL        , &void_func1   ,   NULL        , (int  *)parameter1        , (void *)parameter2    , (void *)return_param      } ,
    { 2 ,   NULL        ,   NULL        , &void_func2   , (int  *)parameter1        , (char *)parameter2    , (void *)return_param      } ,
    { 3 ,   NULL        , &void_func3   ,   NULL        , (short int *)parameter1   , (void *)parameter2    , (void *)return_param      } ,
    { 4 , &int_func     ,   NULL        ,   NULL        , (void *)parameter1        , (void *)parameter2    , (int  *)return_param      } ,
    { 5 ,   NULL        , &int_func1    ,   NULL        , (int  *)parameter1        , (void *)parameter2    , (int  *)return_param      } ,
    { 6 ,   NULL        , &int_func2    ,   NULL        , (float*)parameter1        , (void *)parameter2    , (int  *)return_param      } ,
    { 7 ,   NULL        ,   NULL        , &int_func3    , (int  *)parameter1        , (int  *)parameter2    , (int  *)return_param      } ,
    { 8 , &char_func    ,   NULL        ,   NULL        , (void *)parameter1        , (void *)parameter2    , (char *)return_param      } ,
    { 9 ,   NULL        , &char_func1   ,   NULL        , (int  *)parameter1        , (void *)parameter2    , (char *)return_param      } ,
    { 10,   NULL        ,   NULL        , &char_func2   , (int  *)parameter1        , (int  *)parameter2    , (char *)return_param      } ,
    { 11, &enum_func    ,   NULL        ,   NULL        , (enum_t *)parameter1      , (void *)parameter2    , (void *)return_param      } ,
    { 12,   NULL        ,   NULL        , &enum_func1   , (int  *)parameter1        , (int  *)parameter2    , (enum_t *)return_param    } ,
    { 13, &enum_func2   ,   NULL        ,   NULL        , (str1 *)parameter1        , (void *)parameter2    , (enum_t *)return_param    } 
};

Now in a switch case statement I am trying to call any of the functions:

printf("\nEnter Number of parameters of functions : ");
scanf("%d", ptr1);

printf("\nEnter whether the function has a return value (0/1) : ");
scanf("%d", &ret);

printf("\nWhich function to execute (function id): ");
scanf("%d", &var1);

if (*ptr1 > 0)
    printf("\nEnter the Parameters : \n");

func_id current_func;

for (i=0; i<13; i++){
    if (func_str[i].id == var1) {
        current_func = func_str[i];
        break;
    }
}

switch(*ptr1) {

    case 0: {
        if (ret == 1) {
            printf("\nEntering case 0\n");
            current_func.ret_param = (*current_func.f0)();
        }
        else {
            (*current_func.f0)();
        }
        break;
        }
    /* In actual case the parameters would be read from a memory location and the address of that can be stored in parameter1 */
    case 1: {
        printf("\nEnter Parameter 1: ");
        scanf("%d", parameter1); 
        printf("\nParameter 1 = %d\n",*(int *)parameter1);
        if (ret == 1) {
            current_func.ret_param = (*current_func.f1)(current_func.param1);
        }
        else {
            (*current_func.f1)(current_func.param1);
        }
        break;
        }
    /* In actual case the parameters would be written in a memory location and the address of that can be stored in parameter1 and parameter2 */
    case 2: { 
        printf("\nEnter Parameter 1: ");
        scanf("%d", parameter1);
        printf("\nEnter Parameter 2: ");
        scanf("%d", parameter2);
        if (ret == 1) {
            current_func.ret_param = (*current_func.f2)(current_func.param1, current_func.param2);
            printf("\nReturned parameter : current_func.ret_param = %d", *(int *)current_func.ret_param);
        }
        else {
            (*current_func.f2)(current_func.param1, current_func.param2);
        }
        break;
        }
    default:
        printf("ERROR");
}

In actual case the parameters is written on to a memory location whose address would be assigned with appropriate data-type in the initializing structure.

But the problem I am facing is w.r.t to the data-types of the parameters to be passed/returned while calling the functions. So is there any mechanism for such kind of setup where one can be able to call any function based on number of parameters of any data-type.

Appreciate the help in this regard.

  • 1
    Are you sure C is the right language for this ? – Alexandre C. Sep 09 '11 at 07:15
  • Unfortunately I have to use C language for this. – Navaneet Sep 09 '11 at 07:21
  • 1
    I didn't read all in detail, but casting `int` into `void*` back and forth is certainly not a good idea. They might have different width (on amd64 they have, eg.). If you have to do such things always use `intptr_t`. – Jens Gustedt Sep 09 '11 at 07:25
  • 1
    And having different return types for your functions is particularly dangerous, too. The architecture might have special conventions to return certain types of values in different registers. In such cases it is better to pass a pointer to the return type as argument and to place the result there. – Jens Gustedt Sep 09 '11 at 07:29
  • 1
    is function overloading what you want? http://stackoverflow.com/questions/479207/function-overloading-in-c – steabert Sep 09 '11 at 07:36
  • Yes something like a function overloading... – Navaneet Sep 09 '11 at 12:09

1 Answers1

1

I'd read up on variadic functions, perhaps starting here. They'll let you do what you want. Then I would rewrite all of the functions so that they always pass the variable arguments, and maybe always return values, in void* .

If you used the variable-arguments scheme, you might need only one function: I didn't read your code closely enough to be sure about this. Then you might pass (int) id as the first argument to tell the function unequivocally what to do and how.

Your declaration would then look like (untested) this:

#include <stdarg.h>
void *
the_func ( int id, void *arg1, ... );

and your defintion like (untested) this:

#include <stdarg.h>
void *
the_func ( int id, void *arg1, ... ) {
  #define max_args 10;   
  int i = 0;
  void *args[max_args];
  va_list arglist;
  ...
  // extract incoming args
  va_start( arglist, id );
  while ( i++ < sizeof( args )-1 ) {
    args[i] = va_arg( arglist, void* );
  }
  va_end( arglist );
// now we have all arguments in args[]
    switch ( id ) {  // dispatch on id
    case ....
    } 
Pete Wilson
  • 8,610
  • 6
  • 39
  • 51
  • Thank you Pete for the suggestion. But I cannot change the functions and basically I need a mechanism by which I am able to call any one function whose parameters are put into a defined memory location/s and read them with proper type casting, execute the function and place the result(if any) on to another defined memory location (with proper type casting). – Navaneet Sep 09 '11 at 11:41
  • 1
    You cannot change them, but you can wrap them in order to have them fit into exactly one function sinature scheme. – glglgl Sep 09 '11 at 13:11