17

The question pretty much says it all.

I'm not sure how to do this and haven't come anywhere near anything that works.

Here's some example functions:

add(int x, int y) {
  return x+y;
}

and,

mean(int x1, int y1, int x2, int y2) {
  return (x1 + y1 + x2 + y2) / 4;
}

So far I've tried using typedef with both, but I can't figure how to make something point to one of either type:

typedef int (*mathfunc2)(int x, int y);
typedef int (*mathfunc4)(int x1, int y1, int x2, int y2);

????? func_table[2] = {add, mean};
0

4 Answers 4

45

You need to pick a function pointer type to use as a "generic function pointer", use that type to define your array, and use explicit casts. Casting one function pointer type to another and then back again is guaranteed to preserve the value.

In other words:

typedef int (*generic_fp)(void);

generic_fp func_table[2] = { (generic_fp)add, (generic_fp)mean };

Then to call add, you need to cast it back to the right type:

result = ((mathfunc2)func_table[0])(x, y);

You can define some macros if you find it more palatable:

#define FUNC_2(f, p1, p2) ((mathfunc2)(f))(p1, p2)
#define FUNC_4(f, p1, p2, p3, p4) ((mathfunc4)(f))(p1, p2, p3, p4)

result = FUNC_2(func_table[0], x, y);
Sign up to request clarification or add additional context in comments.

4 Comments

That exactly did the trick! Thanks a bunch, sir. I will hopefully remember this if I ever get 15 reputation and give you an up arrow :)
I was under the impression function pointers behaved differently than regular void pointers because of the parameters. That you couldn't mix function pointers with different parameters because the stack would get corrupted on cleanup. Have I misunderstood something?
@Ioan: You must call the function through a pointer that is compatible with the declared type of the function - which means that if you cast the function pointer to a different type for storage, you must cast it back to the correct type to call the function. The example in this answer does this.
Ah, I see. Good to know the call is what matters, not the storage. Thanks.
5

You could use the Facade Pattern like this:

int add(int x, int y);
int mean(int x1, int y1, int x2, int y2);

typedef int (*operation_fp)(int argc, int* argv);

int add_wrapper(int argc, int* argv) { return add(argv[0], argv[1]); }
int mean_wrapper(int argc, int* argv) { return mean(argv[0], argv[1], argv[2], argv[3]); }

operation_fp func_table[2] = { add_wrapper, mean_wrapper };

Although the code is ugly, it does the job. You should add some validation logic in wrappers.

1 Comment

what about functions that takes different types of arguments? int f1(int x); int f2(char x);
1
int (*func[])() = { add, mean };

1 Comment

Function pointers of type int (*)(int, int) and int (*)(int, int, int, int) are not compatible with function pointers of type int (*)(int, ...).
-2

These two function types are incompatible. Strictly speaking, they could be implemented using completely different argument passing. An implementation might choose, for example, that all functions with up to 3 parameters receive them via registers, and all other functions receive them via the stack.

What you can do though is to define both functions with varargs parameters to make them follow the same parameter passing scheme.

How did you intend to call these functions anyway, not knowing how many parameters they expect?

Comments

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.