23

I have two functions with variable number and types of arguments

double my_func_one(double x, double a, double b, double c) { return x + a + b + c }
double my_func_two(double x, double p[], double c) { return x + p[0] + p[1] + c }

I want to use a pointer to a function to the functions I defined above based on a some condition getting true e.g.

if (condition_1)
   pfunc = my_func_one;
else if (condition_2)
   pfunc = my_func_two;

 // The function that will use the function I passed to it
 swap_function(a, b, pfunc);

My question is, for this scenario, Can I at all define a function pointer? If yes, how?
My understanding is that the prototype of function pointer should be the same for all those functions it CAN be pointed to.

typedef double (*pfunction)(int, int);

In my case they are not the same. Is there any other way to do this?

Language

I am developing in C and I am using gcc 4.4.3 compiler/linker

2
  • 3
    Make the function pointer a void *, and then do proper typecasting when being called? You loose all manner of type-safety though. Commented May 27, 2013 at 10:01
  • It's illegal to cast function pointers to void * if I'm not mistaken Commented Oct 13, 2024 at 6:55

6 Answers 6

35

The cleanest way to do it is to use a union:

typedef union {
  double (*func_one)(double x, double a, double b, double c);
  double (*func_two)(double x, double p[], double c);
} func_one_two;

Then you can initialize an instance of the union, and include information to the swap_function function to say which field is valid:

func_one_two func;

if (condition_1)
   func.func_one = my_func_one;
else if (condition_2)
   func.func_two = my_func_two;

 // The function that will use the function I passed to it
 swap_function(a, b, func, condition_1);

This assumes that swap_function can know based on condition_1 being false that it should assume condition_2. Note that the union is passed by value; it's only a function pointer in size after all so that's not more expensive than passing a pointer to it.

Sign up to request clarification or add additional context in comments.

Comments

13

My question is, for this scenario, Can I at all define a function pointer?

No. (Other than by dirty typecasting.)

Is there any other way to do this?

Your best bet is to create a wrapper function for one of your existing functions. For example:

double my_func_one_wrapper(double x, double p[], double c) {
    return my_func_one(x, p[0], p[1], c);
}

That way, you have two functions with the same signature, and therefore the same function-pointer type.

Comments

3

An old topic but I am facing same issue and finally came with this idea.

If you want the same prototype for each functions you can wrap the parameters in structure like this :

 typedef struct {
     double a,
            b,
            c; 
 }chunk1_t;

  typedef struct {
     double p[];
     double c; 
 }chunk2_t;

Then your function pointer becomes:

 double (*pfunc) (double x, void *args);

which leads to something like this :

 pfunc cb;

 double swap_function(double x, pfunc cb, void *args);

 double my_func_one(double x, void *args) { 
   chunk1_t *chunk = (chunk1_t*) args;
   return x + chunk->a + chunk->b + chunk->c; 
 }

 double my_func_two(double x, void *args) {
   chunk2_t *chunk = (chunk2_t*) args;
   return x + chunk->p[0] + chunk->p[1] + chunk->c ;
 }

 int main(){
   // declare a, b,...
   double a = 1.0f;
   //...
   // cast for safety
   chunk1_t myChunk1 = {(double)a, (double)b, (double)c};
   // don't if you like risk
   chunk2_t myChunk2 = {p, c};

   swap_function(x, cb, &myChunk1); 
   swap_function(x, cb, &myChunk2);
 }

Using function pointer stored in structure:

 #define FUNC_ONE_METHOD 1
 #define FUNC_TWO_METHOD 2

 typedef struct chunk{
     double a, b, c;
     double p[];
     int method;
     double (*pfunc) (double x, struct chunk *self);
 }chunk_t;

 double swap_function(double x, chunk_t *ch){
    switch (ch->method)
    {
        case FUNC_TWO_METHOD:
            ch->pfunc = my_func_two;
            break;
        case FUNC_ONE_METHOD:
            ch->pfunc = my_func_one;
            break;
        default:
            return -1; // or throw error
    return ch->pfunc(x, ch);
 }


 chunk c = {.a= 1, .b=3, .c=1, .method=1};
 swap_function(x, &c);

Comments

1

Your understanding is true.
The signature of your function-pointer must match the corresponding function(s).

Consider learncpp.com:

Just like it is possible to declare a non-constant pointer to a variable, it’s also possible to >declare a non-constant pointer to a function. The syntax for doing so is one of the ugliest things >you will ever see:

// pFoo is a pointer to a function that takes no arguments and returns an integer 
int (*pFoo) (); 

The parenthesis around *pFoo are necessary for precedence reasons, as int *pFoo() would be interpreted as a function named pFoo that takes no parameters and returns a pointer to an integer.

In the above snippet, pFoo is a pointer to a function that has no parameters and returns an integer. pFoo can “point” to any function that matches this signature.

...

Note that the signature (parameters and return value) of the function pointer must match the signature of the function.

2 Comments

well, actually pFoo is a pointer to a function that can take an arbitrary amount of parameters of any type. see godbolt.org/z/Y8M3jP
Lars M. said "actually pFoo is a pointer to a function that can take an arbitrary amount of parameters of any type". That was true at the time, but as of C23 int (*pFoo) (); means no arguments as opposed to "unspecified arguments" as in C11 and earlier.
1

What you want is possible, but a bit dirty. Function pointers can be cast to one another without losing information. The important thing is that you'd always have to call a function through such a pointer only with a signature that corresponds to its definition. So if you cast back before calling the function(s) and call with the correct arguments, all should be fine.

Comments

-2

A sample of Typecasting approach for using a same function pointer for different functions of different prototypes. <>

#include <stdio.h>
typedef void (*myFuncPtrType) (void);

typedef int (*myFunc2PtrType)(int, int);

typedef int * (*myFunc3PtrType)(int *);

static void myFunc_1 (void);
static int myFunc_2 (int, int);
static int* myFunc_3 (int *);

const myFuncPtrType myFuncPtrA[] = {
                                    (myFuncPtrType)myFunc_1,
                                    (myFuncPtrType)myFunc_2,
                                    (myFuncPtrType)myFunc_3
};

static void myFunc_1 (void)
{
    printf("I am in myFunc_1 \n");
}

static int myFunc_2 (int a, int b)
{
    printf("I am in myFunc_2\n");
    return (a+b);
}

static int* myFunc_3 (int *ptr)
{
    printf("I am in myFunc_3\n");
    *ptr = ((*ptr) * 2);
    return (ptr+1);
}

int main(void) {
    // your code goes here
    int A[2],C;

    int* PTR = A;

    (*(myFuncPtrA[0]))();

    A[0]=5;
    A[1]=6;

    C = ((myFunc2PtrType)(*(myFuncPtrA[1])))(A[0],A[1]);

    printf("Value of C: %d \n", C);

    printf("Value of PTR before myFunc_3: %p \n", PTR);
    printf("Value of *PTR before myFunc_3: %d \n", *PTR);

    PTR = ((myFunc3PtrType)(*(myFuncPtrA[2])))(&A);

    //Lets look how PTR has changed after the myFunc_3 call

    printf("Value of PTR after myFunc_3: %p \n", PTR);
    printf("Value of *PTR after myFunc_3: %d \n", *PTR);


    return 0;
}

1 Comment

Could you please add a description of what you have done ? Instead of just pasting the code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.