1

I would like to have an array of function pointers, each pointing to a differ function. The function could differ also in the prototype, and number of parameters.

I am looking for the following similar functionality in C/C++.

The following code is not compilable in C

#include <stdio.h> typedef int (*FUNC)(int a,int b); int func_one(int a) { printf("\n In function 1 with 1 parameter %d \n",a); return 1; } int func_two(int a,int b) { printf("\n In function 2 with 2 parameter %d %d \n",a,b); return 2; } typedef struct{ FUNC fnc; enum type{ ONE,TWO} type_info; }STR; int main() { STR str[2]; int ret; int i; str[0].fnc = func_one; str[0].type_info = ONE; str[1].fnc = func_two; str[1].type_info = TWO; for(i=1;i>=0;--i) { if(str[i].type_info == ONE) ret = str[i].fnc(10); else if(str[i].type_info == TWO) ret = (str[i].fnc)(10,20); else perror("error in implementation \n"); printf("\n return value is %d \n",ret); } return 0; } 
1
  • 1
    I'm having quite a bit of difficulty imagining a real use case for this. If you do have one, consider using boost::function. Commented Mar 7, 2012 at 15:05

7 Answers 7

6

In C, it is safe to cast from one function-pointer type to another (as long as you cast it back in order to call it), so you can declare a sort of "generic function-pointer type":

typedef void (*GENFUNC)(void); 

and then cast as needed:

GENFUNC tmp = (GENFUNC)&func_two; // cast to generic pointer FUNC two = (FUNC)tmp; // note: have to cast it back! two(0, 1); 
Sign up to request clarification or add additional context in comments.

2 Comments

The same applies for C++, though it's not a great idea in either.
@Xeo: Thanks for the note. I feel like it's more potentially justifiable in C than in C++, since in C it's hard to make this any safer. Other answerers below suggest the use of a union, but I don't think that really adds any safety.
1

This doesn't seem like a great idea. But if you really need this, then you should consider using a union:

typedef struct{ union{ int (*f1)(int); int (*f2)(int,int); } fnc; enum type{ ONE,TWO} type_info; }STR; 

4 Comments

I wouldn't do that. You can do the same with a function with variable arguments.
function pointer just stores the address of the function right. Why does C/C++ DO NOT allow me store just the address (like a void* pointer for all data types) ? Is there not a generic function pointer like void* ?
@vamsi: Because it would defeat the purpose of type-safety.
@vamsi a generic pointer must be casted first. however, if the return types and first arguments of the functions are the same, you can use a variable argument function, like I do in my answer.
0

If you know all the different possible types, you could do like this:

typedef int (*FUNC1)(int a); typedef int (*FUNC2)(int a,int b); typedef struct{ union { FUNC1 one_arg; FUNC2 two_arg; } fnc; enum type{ ONE,TWO} type_info; } STR; 

If you don't know them, but whenever you use it, you can somehow manage to figure out the correct form, you can simply use:

typedef struct{ void *fnc; enum type{ ONE,TWO} type_info; } STR; 

Or in the very generic form:

typedef struct{ void *func; char *return_type; char *args_type; } STR; 

where type is a string with each k-letters showing one possible argument type. Same with return_type except it can also contain "v" for void.

Then whenever you want to use the function, you have to look at the return_type and args_type and decide what prototype to case func to. This is, somewhat, similar to name mangling done in C++ (although with name mangling, the function name itself is decorated with args_type symbols rather than keeping another string for it)

Comments

0
typedef int (*FUNC)(void); typedef int (*FUNC_1p)(int); typedef int (*FUNC_2p)(int, int); typedef struct { FUNC fnc; enum type { ONE, TWO } type_info; } STR; 

...

 if ( str[i].type_info == ONE ) { FUNC_1p f = str[i].fnc; ret = f(10); } else if ( str[i].type_info == TWO ) { FUNC_2p f = str[i].fnc; ret = f(10,20); } 

It compiles and run. Not a great idea though.

Comments

0

Your "generic" function in C would take a void* pointer and then you have to cast the void* to data.

You can create several different specially typed versions of this that will always operate on a "known" type so they can cast the void* to the specific type for that function, but the signature would be that of taking a void* parameter so you can store a number of them in a function array.

e.g.

typedef int (GENERIC_FUNC*)(void* genericData); struct A { int x; int y; }; int GenericAFunc( void * ptr ) { A* a = (A*)(ptr); return a->x + a->y; } GENERIC_FUNC * funcs[1]; funcs[0] = GenericAFunc; 

The functions will all return int but they could also set a result in the A struct if you wanted them to generate a different result set.

Comments

0

Define the function as taking variable number of arguments:

typedef int (*FUNC)(int a, ...); 

Then simply cast to a FUNC:

str[0].fnc = (FUNC) func_one; str[1].fnc = (FUNC) func_two; 

And you can call func just like you currently are:

if(str[i].type_info == ONE) ret = str[i].fnc(10); else if(str[i].type_info == TWO) ret = str[i].fnc(10,20); 

This is possible because the variable argument function allows you to pass as many integers as you'd like to it.

6 Comments

That's not necessarily portable; the standard doesn't mandate that the stack is arranged the same for vararg functions as it is for "normal" functions. It also completely eliminates even the most basic type checking the compiler could do.
@OliCharlesworth why not? I haven't seen a C implementation that doesn't support variable argument functions. And, at least with GCC, and all other compilers I've dealt with, the arguments are passed the same way.
I'm not claiming that I know of such a compiler, but there may well be one. TBH, the lack of argument type-checking is more of a turn-off for me...
@RichardJ.RossIII - what you have so far is valid. But, the key question is: what do you intend to do with the pointer? Can you add how you would invoke the pointed-to-function?
Thanks. Your calls invoke undefined behavior in C++ (don't know about C). C++03, §5.2.10/6: "The effect of calling a function through a pointer to a function type (8.3.5) that is not the same as the type used in the definition of the function is undefined." The cast is legal, but you must cast it back to the original type before the call.
|
0

I'm not sure if this fits your real-world requirements, but you could use functors derived from a common base class:

#include <cstdio> struct FUNC { enum type {INVALID, ONE, TWO} type_info; virtual int operator()(int) { return -1; } virtual int operator()(int, int) { return -1; } FUNC(type t=INVALID) : type_info(t) {} }; struct func_one : FUNC { func_one() : FUNC(ONE) {} int operator()(int) { return 1; } }; struct func_two : FUNC { func_two() : FUNC(TWO) {} int operator()(int, int) { return 2; } }; int main () { FUNC* str[2] = { new func_one(), new func_two() }; int ret; int i; for(i = 1; i>=0; --i) { if(str[i]->type_info == FUNC::ONE) ret = (*str[i])(10); else if(str[i]->type_info == FUNC::TWO) ret = (*str[i])(10,20); else throw 1; printf("Return value is %d\n", ret); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.