I need to declare an array of pointers to functions like so:
extern void function1(void);
extern void function2(void);
...
void (*MESSAGE_HANDLERS[])(void) = {
cdecl
says:
cdecl> explain void (* const foo[])(void)
declare foo as array of const pointer to function (void) returning void
Is it what you need?
In situations like this, do a typedef
to name your function signature, that makes it far simpler:
typedef void MESSAGE_HANDLER(void);
with that in place, it should be just:
MESSAGE_HANDLER * const handlers[] = { function1, function2 };
To get the actual content of the array constant.
EDIT: Removed pointer part from the typedef
, this really is better (live and learn).
With VisualStudio 2008, I get:
void (* const MESSAGE_HANDLERS[])(void) = {
NULL,
NULL
};
int main ()
{
/* Gives error
'=' : left operand must be l-value
*/
MESSAGE_HANDLERS = NULL;
/* Gives error
l-value specifies const object
*/
MESSAGE_HANDLERS[0] = NULL;
}
I am not sure if this will work in 'C'. it does work in 'C++':
First define MESSAGE_HANDLERS as a type:
typedef void (*MESSAGE_HANDLER)();
Then, use the type definition to declare your array a constant:
MESSAGE_HANDLER const handlers[] = {function1, function2};
The trick is in the typedef
, if you can do the same semantically in 'C', it should work too.
There is a technique to remember how to build such type. First try to read pointers starting from their name and read from right to left.
T t[5];
is an array of 5 T. To make T a function type, you write the return-type to the left, and the parameters to the right:
void t[5](void);
would be an array of 5 functions returning void and taking no parameters. But functions itself can't be stuffed in arrays! They are not objects. Only pointers to them can.
What about
void * t[5](void);
That's still wrong as it would just change the return-type to be a pointer to void. You have to use parentheses:
void (*t[5])(void);
and this will actually work. t is an array of 5 pointers to functions returning void and taking no parameters.
Great! What about an array of pointers to arras? That's very similar. The element type appears at the left, and the dimension at the right. Again, parentheses are needed because otherwise the array would become a multidimensional array of integer pointers:
int (*t[5])[3];
That's it! An array of 5 pointers to arrays of 3 int.
What we have just learned is true about functions too. Let's declare a function taking an int that returns a pointer to another function taking no parameter and returning void:
void (*f(int))(void);
we need parentheses again for he same reason as above. We could now call it, and call the returned function pointed to again.
f(10)();
What about this?
f(10)(true)(3.4);
? In other words, how would a function taking int returning a pointer to a function taking bool returning a pointer to a function taking double and returning void would look like? The answer is that you just nest them:
void (*(*f(int))(bool))(double);
You could do so endless times. Indeed, you can also return a pointer to an array just like you can a pointer to a function:
int (*(*f(int))(bool))[3];
This is a function taking int returning a pointer to a function taking bool returning a pointer to an array of 3 int
Now that the above explained how to build up complexer types from fundamental types, you can put const
at places where you now know where they belong to. Just consider:
T c * c * c ... * c name;
The T
is the basic type that we end up pointing to at the end. The c
stands for either const or not const. For example
int const * const * name;
will declare name to have the type pointer to a constant pointer to a constant int. You can change name
, but you cannot change *name
, which would be of type
int const * const
and neither **name
, which would be of type
int const
Let's apply this to a function pointer of above:
void (* const t[5])(void);
This would actually declare the array to contain constant pointers. So after creating (and initializing) the array, the pointers are const, because the const
appeared after the star. Note that we cannot put a const
before the star in this case, since there are no pointers to constant functions. Functions simply can't be const as that would not make sense. So the following is not valid:
void (const * t[5])(void);
The C++ and C way of declaring functions and arrays actually is actually a bit confusing. You have to get your head around it first, but if you understand it, you can write very compact function declarations using it.