Initialize global array of function pointers at either compile-time, or run-time before main()
I was going to suggest this question is more about C, but on second thoughts, what you want is a global container of function pointers, and to register available functions into it. I believe this is called a Singleton (shudder).
You could make myfunc_array
a vector, or wrap up a C equivalent, and provide a function to push myfunc
s into it. Now finally, you can create a class (again you can do this in C), that takes a myfunc
and pushes it into the global array. This will all occur immediately prior to main being called. Here are some code snippets to get you thinking:
// a header
extern vector<myfunc> myfunc_array;
struct _register_myfunc {
_register_myfunc(myfunc lolz0rs) {
myfunc_array.push_back(lolz0rs);
}
}
#define register_myfunc(lolz0rs) static _register_myfunc _unique_name(lolz0rs);
// a source
vector<myfunc> myfunc_array;
// another source
int16_t myfunc_1() { ... }
register_myfunc(myfunc_1);
// another source
int16_t myfunc_2() { ... }
register_myfunc(myfunc_2);
Keep in mind the following:
- You can control the order the functions are registered by manipulating your link step.
- The initialization of your translation unit-scoped variables occurs before main is called, i.e. the registering will be completed.
- You can generate unique names using some macro magic and
__COUNTER__
. There may be other sneaky ways that I don't know about. See these useful questions:- Unnamed parameters in C
- Unexpected predefined macro behaviour when pasting tokens
- How to generate random variable names in C++ using macros?
How to make a function which returns a function pointer in an array of function pointers
The proper definition for the array would be:
void (* const function_list[FUNCITON_NUM])(int input, int *output) = ...
And for get_function_by_index
would be:
void (*get_function_by_index(int func_id))(int, int*)
When passing or returning function pointers, it's very helpful to have a typedef for the function pointer type to make it easier to manage.
The typedef
can be created in messy_functs.h for the function pointer type:
typedef void (*messy_func)(int, int *);
Then in messy_funct.c, use this type for the array:
const messy_func function_list[FUNCITON_NUM] = {func1, func2, func3, func_m, ... };
And for the return type of get_function_by_index
messy_func get_function_by_index(int func_id) {
return function_list[func_id];
}
And you would call this function like this:
void get_result(int func_idx, int input, int *output)
{
get_function_by_index(func_idx)(input, output);
}
parameters of a function. local or is variable of calling function
int func1(int c,int *d)
{
int *a=&c;
return a;
}
This is completely wrong. The function is declared as returning an int
but you return a pointer to an int
. Furthermore returning a pointer to a parameter is pointless because as soon as the function is terminated, the parameter no longer exists.
int func2(int c,int *d)
{
...
return d;
}
Here again you return a pointer to int
but the function is declared as returning an int
.
int func3(int x)
{
...
int y=x;
return x;
}
This is correct but returning one of the parameters is rather pointless.
Initializing an array of structs (compiler error: initializer element is not constant)
The function definitions are not material to the problem. The type used for func_id
is, though.
Consider this code:
#include <stdint.h>
#define MAX_FUNC_NAME_LEN 6
typedef uintptr_t ptr_t;
typedef struct Funky
{
ptr_t func_id; /* I know this should be intptr_t, but ignore for now ... */
char func_name[MAX_FUNC_NAME_LEN];
} Funky;
double func1(double d1, double d2, double d3);
double func2(double d1, double d2, double d3);
double func3(double d1, double d2, double d3);
double func4(double d1, double d2, double d3);
Funky fk[4] = {
{(ptr_t)func1, "func1"}, /* <- gcc barfs here ... */
{(ptr_t)func2, "func2"},
{(ptr_t)func3, "func3"},
{(ptr_t)func4, "func4"}
};
As written, using uintptr_t
, this compiles cleanly under GCC 4.8.1 on Mac OS X 10.8.4 (64-bit compilation). Change the type of ptr_t
to int
and you get a pile of warnings. The trouble is that the 64-bit address constants don't fit into a 32-bit int
, so the loader would have to generate code to truncate the addresses, which makes them insufficiently constant. With a 32-bit compilation, the code using int
compiles cleanly too.
So, use a big enough type (uintptr_t
recommended) and you will be OK. The "I know it should be intptr_t
but ignore for now" comment is the source of your trouble; don't ignore it.
Related Topics
Relative Paths Not Working in Xcode C++
Displaying Svg in Opengl Without Intermediate Raster
How to Block Running Two Instances of the Same Program
How to Iterate Over a Std::Tuple in C++ 11
What's the Easiest Way to Generate Xml in C++
What Does 'Return *This' Mean in C++
Project Error: Unknown Module(S) in Qt: Webkitwidgets
Do I Have to Bind a Udp Socket in My Client Program to Receive Data? (I Always Get Wsaeinval)
Boost::Property_Tree Xml Pretty Printing
C++ #Include and #Import Difference
Why Can't We Declare a Namespace Within a Class
Error: Class Has Not Been Declared Despite Header Inclusion, and the Code Compiling Fine Elsewhere
What Is the Meaning of Template<> with Empty Angle Brackets in C++
Why Do We Have Reinterpret_Cast in C++ When Two Chained Static_Cast Can Do Its Job