Initialize Global Array of Function Pointers at Either Compile-Time, or Run-Time Before Main()

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 myfuncs 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



Leave a reply



Submit