I need to declare an array of pointers to functions like so:
extern void function1(void);
extern void function2(void);
...
void (*MESSAGE_HANDLERS[])(void) = {
function1,
function2,
...
};
However, I want the the array to be declared as constant -- both the data in the array and the pointer to the data. Unfortunately, I do not recall where to place the const key-word(s).
I'm assuming the actual pointer, MESSAGE_HANDLERS in this case, is already constant because it is declared as an array. On the otherhand, couldn't the function pointers within the array be change at runtime if it is declared as shown?
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.
How to declare that stuff without help?
Arrays
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 about functions?
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)();
Returning a pointer to function returning another pointer to function
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
What does it have to do with const?
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);
Conclusion
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.
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).
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?
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.
Related
I'm confused about the meaning of void *function().
Is it a pointer to function or a function returning void*? I've always used it on data structures as a recursive function returning a pointer, but when i saw a code in multithreading (pthread) there is a same function declaration. Now I'm confused what's the difference between them.
The function has the return type void *.
void *function();
So I always prefer in such cases to separate the symbol * from the function name like
void * function();
And as Jarod42 pointed to in a comment you can rewrite the function declaration in C++ using the trailing return type like
auto function() -> void *;
If you want to declare a pointer to function then you should write
void ( *function )();
where the return type is void Or
void * ( *function )();
where the return type void *.
Or a pointer to function that returns pointer to function
void * ( *( *function )() )();
Whenever I'm unsure about C syntax issues, I like to use the cdecl utility (online version) to interpret for me. It translates between C syntax and English.
For example, I input your example of void *foo() and it returned
declare foo as function returning pointer to void
To see what the other syntax would look like, I input declare foo as pointer to function returning void and it returned
void (*foo)()
This gets particularly useful when you have multiple levels of typecasts, stars, or brackets in a single expression.
It is a function returning a pointer to void.
Think of your declaration this way:
void *(function());
This would be a function returning void (or nothing):
void (*function2)();
Think of the above declaration this way:
void ((*function2)());
A much easier way to write these is to use typedefs:
typedef void *function_returning_void_pointer();
typedef void function_returning_nothing();
function_returning_void_pointer function;
function_returning_nothing *function2;
This generally eliminates the confusion around function pointers and is much easier to read.
Declarations in C/C++ are read from the identifier outwards following operator precedence.
A quick look at the C/C++ operator precedence table in wikipedia reveals that the function call operator () has a higher precedence than the indirection operator *. So, your function declarations reads like this:
Start at the identifier: function is
function() a function that takes no arguments
void* function() and returns a void*.
This general principle also holds with array declarations ([] also has higher precedence than *) and combinations of the two. So
int *(*arr[42])();
is read as
arr is
arr[42] an array of 42 elements which are
*arr[42] pointers to
(*arr[42])() functions that take no arguments and
int *(*arr[42])() return an int*.
It takes a bit to get used to this, but once you've understood the principle, it's easy to read those declarations unambiguously.
So I have two functions that does the same thing but on different type variables.
The first function fills up an array of integers when given an int arr[] argument.
The second function fills up a linked list with integers also when given a struct as an argument.
The struct for the linked list argument looks something like this
typedef struct {node_t *head;int size;}
list_t;
Now I have implemented a table of function pointers for the two functions as such:
typedef struct{
char *name; //name of the function
void (*fill)(int arr[]); //fill up the array
} alg_t;
alg_t algs[] = {
{"func1",fill_up_arr},
{"func2",fill_up_linkedList}
};
Notice that inside the struct that holds my pointers, the fill function pointer
takes int arr[] as an argument.
I only want one pointer of a function in that struct, is there a way I can use
typecasting so that other functions such as fill_up_linkedList require argument to be of type list_t instead of int arr[]?
//This is what I want my main to look like.
//I want func.fill to be called only once thus
//dynamically perform the operations for all functions inside the table of
//functions array
int arr = malloc(sizeof(int)algs.size);
for(int i = 0; i<algs.size;i++){
alg_t func = algs[i];
func.fill(arr);
}
It seems that the problem with this code would be when the loop would try and perform the fill_up_LinkedList function as it needs a different argument.
How can I use a typecast in this situation?
Thanks
The good news
C11 §6.3.2.3 Pointers ¶8 (under the general topic §6.3 Conversions) says:
A pointer to a function of one type may be converted to a pointer to a function of another
type and back again; the result shall compare equal to the original pointer. If a converted
pointer is used to call a function whose type is not compatible with the referenced type,
the behavior is undefined.
That means you can store any and all function pointers in a common function pointer type, for example typedef void (*GenericFunctionPointer)(void). What is crucial, though, is that you convert from that generic function pointer type back to the correct function pointer type before you invoke the function via the pointer (and that you provide the correct argument list, and that you handle the return type appropriately, though ignoring the return value, if any, is always an option).
The bad news
For two different function pointer types, each with one instance of the the function, the infrastructure needed to support this is probably more elaborate than the savings, if any. On the other hand, if you have two or more different function pointer types, and most if not all of the types have many representative functions ('many' meaning 'more than one', as in the computer engineer's counting: "zero, one, many"), then the infrastructure can pay off. One of the issues is marshalling the function arguments — how are the arguments made accessible so that the function can be called via the pointer with the correct arguments.
So, doing things this way is complex and verbose.
The stated requirement
In a comment, the OP Moi says:
I only want to put one function in the struct. My goal is to find a way to allow fillArray to allow the passing of different args.
I have major reservations about the use of an uncounted array as the argument list as shown in the question — void (*fill)(int arr[]) is shown. In my view, it should be void (*fill)(size_t n, int arr[n]), using the variable length array notation. You can omit the n in the subscript if you wish — void (*fill)(size_t n, int arr[]) — or even use void (*fill)(int arr[], size_t n), which is the more classic order for the arguments.
Putting this concern aside, if you want a single function to accept different arguments, one way to achieve that is with void * as the type, but you have to be aware of the problems — one of which is type safety. You'll also need to borrow ideas from the standard C functions qsort() and bsearch(). The argument list will include the pointer to the start of the array as a void *, the size of each element of the array, and the number of elements in the array. You may also need analogues to the comparator functions.
Internal to the single called function, though, you will probably end up with two code paths, so although you call a single function via the pointer, you end up doing the equivalent of implementing two functions. You could use an interface similar to qsort()'s so that the two functions have the same interface and different bodies, and you use two pointers in the alg_t array.
Summary
You probably can't achieve the stated requirement cleanly.
You will probably need two logically separate functions to handle the two separate interfaces, even if you smush all the code inside a single function.
Use a union:
typedef struct {
char *name; //name of the function
union {
void(*fillArray)(int arr[]); //fill up the array
void(*fillList)(YourListType list); //fill up the list
};
} alg_t;
alg_t a;
a.fillArray(...);
a.fillList(...);
Or:
typedef struct {
char *name; //name of the function
union {
void(*fillArray)(int arr[]); //fill up the array
void(*fillList)(YourListType list); //fill up the list
} functions;
} alg_t;
alg_t a;
a.functions.fillArray(...);
a.functions.fillList(...);
Since you only have 2 types, you can just use an enum and a macro
enum e_type {e_foo,e_bar};
#define do_foobar(e,...) (e)?bar(__VA_ARGS__):foo(__VA_ARGS__)
replace foo and bar with your function names
If you only have the problem with the function parameters and not with the return value, there's a trick related to incomplete type definitions. The trick consists in leaving empty the list of parameters in the pointer type declaration, as in:
typedef void (*callback_ptr)();
which is different from:
typedef void (*callback_ptr)(void);
in the first case, the compiler will not check the parameters passed to the function, as the pointer is a pointer to an incompletely defined function type, while the second explicitly says the function doesn't require parameters and will give you an error if you try to call it with them.
I'm trying to learn c, so I tried reading some source code.
But I have no idea what this might mean:
static const char*(*const functab[])(void)={
ram,date
};
The first part, static const char* is fine, as it seems to be a function (has an argument of type void), static should mean that it is only visible in this file and const char* should mean that the value cannot be changed but the address can be changed.
But in that case, it doesn't make sense after the last part following the function name, as it was the case with
static const char * date(void);
static const char * ram(void);
Instead of the function name there is (*const functab[]), a const array called functab containing addresses?
Is this some kind of wrapping function containing the functions ram and date? Some alternative way of declaring arrays?
functab is an array of function pointers (array of const function pointers, to be exact), which returns const char* and accepts no arguments.
Later,
... = { ram, date };
is a brace-enclosed initializer list which serves as the initializer for the array.
This is the way to define array of function pointers in C. So instead of calling function as ram(), using this array you can call it by (* functab[1]).
Below discussion has good examples of array of function pointer:
How can I use an array of function pointers?
Short answer: Here functab is an array of function pointers, and the array is initialized with pointers to functions ram and date. This also explains the name functab which is likely from "FUNCtion TABle".
Long answer: In C you can get a pointer to a function and save it to a variable. A variable used in this fashion is known as a function pointer.
For example, funcptr variable below will contain the address of do_stuff's entry point:
int do_stuff(const char* x) { ...do stuff.. }
...
ftype_t funcptr = &do_stuff;
...
(*funcptr)("now"); // calls do_stuff()
This will only work if you have already defined the type of funcptr, which is ftype_t here. The type definition should take this form:
typedef int (*ftype_t)(const char*);
In English, this means ftype_t is being defined as a type of function that takes const char* as its only argument and returns int.
If you didn't want to typedef only for this, you could have achieved the same thing by doing below:
int (*funcptr)(const char*) = &do_stuff;
This works, but its syntax is confusing. Also it gets quite ugly if you attempt to do something like building an array of function pointers, which is exactly what your code does.
Shown below is equivalent code, which is much easier to understand:
typedef static const char*(*myfn_t)(void);
const myfn_t functab[] = { &ram, &date };
(The & (address of) is usually optional, but recommended. )
Complex variable declarations need to be read inside out in C:
functab is the identifier of the variable, so we start reading here...
functab[] it is an array...
*const functab[] of constant pointers...
(*const functab[])(...) to functions...
(*const functab[])(void) that take no arguments...
const char*(*const functab[])(void) but return a const char*.
The meaning of static depends on whether it's outside or inside of a function. If it's outside, the static means that functab is declared with file scope (i.e. a global variable that's only visible inside a single .c file). If it's inside a function, it means that functab is a global variable that's only visible inside that function.
The = { ram, date } initialize the array with two members. Both ram and date should be functions that are declared as const char* ram(void).
The effect of this declaration is, that the following function calls are equivalent:
const char* result = ram();
const char* result = functab[0]();
Let's say I have an array of arrays of function pointers. In other words, I might want to call a matrix transpose function like so, depending upon what dtype my matrix is:
Transp[dtype][index_dtype](A.ia, A.a, B.ia, B.a);
Functions in Transp might look like this:
void transp_i64_i8(const int64_t* ia, const int8_t* a, int64_t* ib, int8_t* b) {
// transpose here
return;
}
except varying the pointer types.
It seems to me that I should declare my function pointer array like so:
void (**Transp)(const void* ia, const void* a, const void* ib, const void* b)[DTYPES_MAX][INDEX_TYPES_MAX] = {
{transp_i8_i8, transp_i8_i16, transp_i8_i32, /* ... */ },
{transp_i16_i8, transp_i16_i16, /* ... */ },
{transp_i32_i8, transp_i32_i16, /* ... */ },
/* ... */
}
Unfortunately this doesn't seem to work:
error: called object ‘Transp[(int)self_m->storage->dtype][(int)((struct YALE_STORAGE *)self_m->storage)->index_dtype]’ is not a function
../../../../ext/nmatrix/nmatrix.c: In function ‘nm_complex_conjugate_bang’:
../../../../ext/nmatrix/nmatrix.c:1910:32: error: subscripted value is neither array nor pointer nor vector
I found one fairly useful reference, but I really need an example for my exact use-case to understand and apply.
So what, exactly, is the correct way to define an array of arrays of function pointers? Specifically, how is the declaration portion written?
(I realize this can be done with a typedef much more easily, but I'm writing a code generator, and would rather not use a typedef.)
You declare it in a similar way to how you would use it, e.g.:
void (*Transp[DTYPES_MAX][INDEX_TYPES_MAX])(const int64_t*,
const int64_t*,
const int64_t*,
const int64_t*);
So the type of a function pointer is
ReturnType (*)(Args);
The type of an array of function pointers is
ReturnType (*[n])(Args);
So an array of arrays of function pointers would be
ReturnType (*[n][m])(Args);
Comparing this to what you have, it looks like you're declaring your array as
ReturnType (**)(Args)[n][m];
That is, a pointer to a pointer to a function that returns an array of arrays. If you remove one of the stars from your variable declaration and move the arrays inside the parentheses, I think this will resolve the problem.
Hope this helps!
If your function pointers all have a fixed number of parameters but different number of parameters or different parameter types, you cannot anyway portably use a single type of function pointers to represent all the function pointers.
In POSIX system you can use an array of array of void * as POSIX guarantees the representation of function pointers and void * is the same. In C actually there is no conversion between function pointers and void * but compilers usually support it.
Pointers can be declared as pointing to mutable (non-const) data or pointer to constant data.
Pointers can be defined to point to a function.
My coworkers and I were discussing the use of "const" with pointers and the question came up regarding the use of const with function pointers.
Here are some questions:
What is the meaning of a pointer to a constant function versus a
pointer to a non-constant function?
Can a function be const?
Can a function be non-const (mutable)?
What is the proper (safe) syntax for passing a function pointer?
Edit 1: Function pointer syntax
typedef void (*Function_Pointer)(void); // Pointer to void function returning void.
void function_a(Function_Pointer p_func); // Example 1.
void function_b(const Function_Pointer p_func); // Example 2.
void function_c(Function_Pointer const p_func); // Example 3.
void function_d(const Function_Pointer const p_func); // Example 4.
The above declarations are examples of treating a function pointer like a pointer to an intrinsic type.
A data, variable or memory pointer allows for the above combinations.
So the questions are: can a function pointer have the same combinations and what is meant by a pointer to a const function (such as Example 2)?
In C, there's no such thing as a function being const or otherwise, so a pointer to a const function is meaningless (shouldn't compile, though I haven't checked with any particular compiler).
Note that although it's different, you can have a const pointer to a function, a pointer to function returning const, etc. Essentially everything but the function itself can be const. Consider a few examples:
// normal pointer to function
int (*func)(int);
// pointer to const function -- not allowed
int (const *func)(int);
// const pointer to function. Allowed, must be initialized.
int (*const func)(int) = some_func;
// Bonus: pointer to function returning pointer to const
void const *(*func)(int);
// triple bonus: const pointer to function returning pointer to const.
void const *(*const func)(int) = func.
As far as passing a pointer to a function as a parameter goes, it's pretty simple. You normally want to just pass a pointer to the correct type. However, a pointer to any type of function can be converted to a pointer to some other type of function, then back to its original type, and retain the original value.
According to the C spec (C99, section 6.7.3):
The properties associated with qualified types are meaningful only for
expressions that are lvalues.
When the spec says "qualified types", it means things defined with the const, restrict, orvolatile keyword. Snice functions are not lvalues, the const keyword on a function isn't meaningful. You may be looking at some sort of compiler-specific extension. Some compilers will throw an error if you try to declare a function as const.
Are you sure that you're looking at a pointer to a constant function and not a constant pointer to a function (that is, it's the pointer that's const, not the function)?
Regarding #4: see this guide for a helpful overview of creating, passing, and using function pointers.
Under C, there is no such thing as a const function. const is a type-qualifier, and so can only be used to qualify a type, not a function. Maybe you mean a const pointer to a function or a non-const pointer to a function?
In C++, methods can be const. If a method is const, it means that after you call that method, the object containing the method will be in the same state as before you called the method (none of the instance variables[1] have been modified). Thus, you can point to a const method and a non-const method, and those methods are different.
You can accept a function pointer in an argument list as retType (*variableName)(arguments).
[1] Unless they are mutable.
In C, functions can be const if you are in the world of GCC! Functions can be declared const through the use of attributes attached to declarations of functions and other symbols. It is basically used to provide information to the compiler on what the function does, even though its body is not available so that the compiler can do some kind of optimizations with it.
A constant function is generally defined in terms of a pure function.
A pure function is a function with basically no side effect. This
means that pure functions return a value that is calculated based on
given parameters and global memory, but cannot affect the value of any
other global variable. Pure functions cannot reasonably lack a return
type (i.e. have a void return type).
And now we can define what is a const function,
A pure function that does not access global memory, but only its
parameters, is called a constant function. This is because the
function, being unrelated to the state of global memory, will always
return the same value when given the same parameters. The return value
is thus derived directly and exclusively from the values of the
parameters given.
Here const doesn't imply anything about function mutability. But it is a function which doesn't touch global memory. You can assign normal pointers to such functions. Anyways the code region will generally ( forgetting self modifying code for a while ) be RO and you cannot modify it through the normal pointer.
Read the full insightful article here.
So when it comes to GCC Constant functions we are talking about optimizations and not function mutability.
1.What is the meaning of a pointer to a constant function versus a pointer to a non-constant function?
There is no difference between const and non-const: the function itself is not modifiable
Note: In C++ if the function is a member function of a class, const means that the state of the object within this function cannot be changed (member variables assigned to, non-const memeber functions called). In this case the const keyword is part of the member function's signature and therefore makes a difference in terms of the pointer.
2.Can a function be const?
See above.
3.Can a function be non-const (mutable)?
See above
4.What is the proper (safe) syntax for passing a function pointer?
All pointers to free functions can be cast to any other pointer to free function (i.e. their size is the same). So you could define a type for a (hypothetical) function: void f(); and convert all function pointers to this type to store. Note that you should not call the function via this common type: you need to cast it bact to its original pointer-to-function type, otherwise you get undefined behavior (and most likely crash)
For C++: pointers to member functions are not guaranteed to be convertible to pointers to free functions
1.
There is syntactically nowhere to place 'const' to make a function's contents constant.
You will run into 'function is not an l-value' error regardless if you have const or not.
typedef void (* FUNC)(void);
FUNC pFunc;
pFunc = 0; // OK
*pFunc = 0; // error: Cannot assign to a function (a function is not an l-value)
typedef void (* const FUNC)(void);
FUNC pFunc;
pFunc = 0; // error (const)
*pFunc = 0; // error: Cannot assign to a function (a function is not an l-value)
typedef void (const * FUNC)(void); // error: <cv-qualifier> (lol?)
2 & 3.
Function pointers- yes.. Function contents, doesn't look like.
4.
I don't think there is any way to make passing a function pointer safer. With all the consts in the world, the only thing you can protect is that 'SetCallback' can't change it's own local copy of the parameter.
typedef void (* const FUNC)(void);
void SetCallback(const FUNC const pCallback)
{
FUNC pTemp = pCallback; // OK (even though pTemp is not const!!)
pCallback = 0; // error (const)
}