i need to write a function that receives an array of pointers to functions.
i wrote the following code, however i'm having trouble in testing it at the moment.
is this the correct way to define a pointers to function array?
typedef (*Function)(double);
void func(Function* arr);
and if i want to declare the size of the array with [20] do i write:
void func(Function arr[20]);
?
thanks for your help
First, my usual method for figuring out complex types. Start with the identifier, and then add on the rest one step at a time:
f -- f
f[N] -- is an N-element array
*f[N] -- of pointers
(*f[N])() -- to functions
T (*f[N])() -- returning T
For an array of pointers to functions taking a double parameter and returning a double value, that would be
double (*f[N])(double);
However, remember that expressions of array type "decay" from type "N-element array of T" to "pointer to T" in most contexts. When you pass an array expression as an argument to a function, what the function actually receives is a pointer. So, instead of receiving an object of type "N-element array of pointer to function returning double", your function will receive an object of type "pointer to pointer to function returning double", or
double (**f)(double)
So your function definition would look something like
void func(double (**f)(double))
{
int i;
...
for (i = 0; f[i] != NULL; i++)
{
double x = (*f[i])((double) i);
}
}
And the caller would look something like
double a(double x) {...}
double b(double x) {...}
double c(double x) {...}
void foo(void)
{
double (*list[])(double) = {a, b, c, NULL};
func(list);
}
If you want to use typedefs instead, you could use something like this:
typedef double Dblfunc(double); // typedef for function type
typedef Dblfunc *Dblfuncptr; // typedef for function pointer type
void func(Dblfuncptr *f)
{
int i;
for (i = 0; f[i] != NULL; i++)
{
double x = (*f[i])((double) i);
...
}
}
...
void foo(void)
{
Dblfuncptr list[] = {a, b, c, NULL}; // EDIT: fixed type
func(list);
}
Using the typedefs makes the array and function parameter look more like regular types. Personally, I prefer using the "raw" types, since it shows explicitly that I'm dealing with pointers to functions, and it shows what the return and parameter types are.
If you correct the typedef to include a return type typedef void (*Function)(double);, that array declaration will work fine. You'd call it by calling (arr[index])(3.14) for the array case.
BTW: http://www.newty.de/fpt/fpt.html is a handy reference for function pointers.
What does the function return? You're the return type in the function pointer typedef, like you should have something like
typedef double (*Function)(double);
it looks almost correct i think you forgot the return type when declaring Function:
typedef int (*Function)(double)
instead
the second declaration is invalid too i think because it is invalid to specify array size for function parameters
void func (Function*)
will do just fine
Related
In short, my question is: does the C standard allow for an arbitrary function pointer type similar to void * being an arbitrary data pointer type?
It is common to define call-back function types with a void * parameter to pass on an arbitrary data package whose format is known to the call-back function, but not to the caller.
For example:
typedef void (* EventFunctionType)(void *data);
void RegisterEventFunction(EventFunctionType function, void *data);
An "EventFunction" can then be registered with a data pointer which will be passed to the function when it is called.
Now suppose we want to pass a function pointer to the call-back. The function could have any prototype which would be known to the specific call-back function, just like the arbitrary data structure above.
A void * cannot hold a function pointer, so which type could be used?
Note: An obvious solution to this problem would be to wrap the function pointer in a data structure with the correct function pointer type, but the question is if the function pointer could be passed on directly in a generic form which the call-back could then cast to a pointer with the correct prototype?
There are no function pointer type that works the same as/similar to to void-pointer.
But function pointers has another characteristic that can be used. It's already referenced in the answer linked in this question:
In the C11 draft standard N1570, 6.3.2.3 ยง8:
A pointer to a function of one type may be converted to a pointer to a function of another type and back again.
This mean that you can use any function pointer type as your "arbitrary function pointer type". It doesn't matter as long as you know how to get back to the real/original type (i.e. know the original type so that you can cast correctly).
For instance:
typedef void (*func_ptr_void)(void);
and then use func_ptr_void as your "arbitrary function pointer type".
But notice that unlike conversion between void* and other object pointer types, the conversion between function pointers will always require an explicit cast. The code example below shows this difference:
#include <stdio.h>
typedef void (*func_ptr_void)(void);
typedef int (*f_int)(int);
int bar(int n)
{
return n * n;
}
int test(func_ptr_void f, int y)
{
f_int fc = (f_int)f; // Explicit cast
return fc(y);
}
int foo(void* p)
{
int* pi = p; // Explicit cast not needed
return *pi;
}
int main(void)
{
int x = 42;
void* pv = &x; // Explicit cast not needed
printf("%d \n", foo(pv));
func_ptr_void fpv = (func_ptr_void)bar; // Explicit cast
printf("%d \n", test(fpv, 5));
return 0;
}
does the C standard allow for an arbitrary function pointer type similar to void * being an arbitrary data pointer type?
No. Two function pointers are only compatible if their return types and parameters (including qualifiers) match.
However, pointer conversions between any two function pointers by means of a cast are well-defined (6.3.2.3/8) as long as you don't invoke the function through the wrong pointer type. This means that you can use any function pointer type as a "generic function pointer" as long as you keep track of what function that pointer actually points at. Such as using an extra enum for that purpose.
Generally when using function pointers, we don't do that however, but instead define a common interface. For example like the callbacks to bsearch/qsort which use the form int (*)(const void*, const void*).
Here's an example of "keep track of type using enum", which is not something I particularly recommend but otherwise perfectly well-defined:
#include <stdio.h>
static int intfunc (int x)
{
printf("%d\n", x);
return x;
}
static double doublefunc (double x)
{
printf("%f\n", x);
return x;
}
typedef enum
{
INTFUNC,
DOUBLEFUNC
} functype_t;
typedef void generic_func_t (void);
typedef int int_func_t (int);
typedef int double_func_t (double);
typedef struct
{
generic_func_t* fptr;
functype_t type;
} func_t;
void func_call (const func_t* f)
{
switch(f->type)
{
case INTFUNC: ((int_func_t*)f->fptr ) (1); break;
case DOUBLEFUNC: ((double_func_t*)f->fptr) (1.0); break;
}
}
int main (void)
{
func_t f1 = { (generic_func_t*)intfunc, INTFUNC };
func_t f2 = { (generic_func_t*)doublefunc, DOUBLEFUNC };
func_call(&f1);
func_call(&f2);
}
That's "old school" C, but it is not recommended since it is clunky, brittle and not really type safe. In modern C programming we wouldn't write that kind of code however, but replace that whole mess with something like this:
#include <stdio.h>
static int intfunc (int x)
{
printf("%d\n", x);
return x;
}
static double doublefunc (double x)
{
printf("%f\n", x);
return x;
}
#define func_call(obj) \
_Generic((obj), \
int: intfunc, \
double: doublefunc) (obj) \
int main (void)
{
func_call(1);
func_call(1.0);
}
So, I am just trying to wrap my head around "pointer function that returns a pointer to an array"... but to start off slowly, I had to understand this:
void Print(const char c){
printf("\nPrint: %c\n", c);
}
int main () {
void (*FunctionPointer)(const char);
FunctionPointer = &Print;
FunctionPointer('a');
}
Which I do - pretty easy to guess what is going on... FunctionPointer just points to the location where the Print function "resides". Instead of jumping to a specific memory address (stored on a register) of a specific function, I can now be more flexible and point to any function that I want to access.
But I am stuck with the following...
int main () {
int (*FunctionPointer())[];
}
Now it seems that the function that is pointed by FunctionPointer, can in fact return a pointer to an array of type int. The compiler accepts the second line - so far so good - and I also understand the concept... but I am getting stuck regarding the implementation.
FunctionPointer needs - once again, to point to a function. That function can indeed return a pointer that points to an array of type int... soooooo:
int *Array(){
int ar[2] = {5,6};
return ar;
}
int main () {
int (*FunctionPointer())[];
FunctionPointer = &Array;
}
However, the last piece of code is just not accepted by the compiler.... So, what gives?
With
int (*FunctionPointer())[];
you've declared FunctionPointer as a function returning a pointer to an array of int -- not a function pointer. You want
int *(*FunctionPointer)();
If you use [] here, you'll get an error, as functions can't return arrays -- arrays are not first class types -- and unlike with function parameters, arrays will not be silently converted to pointers when used as the return value of a function type. With that, you'll still get the warning
t.c:3:12: warning: function returns address of local variable [-Wreturn-local-addr]
return ar;
^~
which is pretty self-explanatory
You have declared the array of function pointers. Arrays can't be assignable. Functions can't return arrays. You might wish
int* (*FunctionPointer)();
FunctionPointer = &Array;
Function pointers are much easier when you use typedefs. You can simply use the same notation as "normal" data pointers.
// func is a function type. It has one parater and returns pointer to int
typedef int *func(const char);
// funcptr is a pointer to func
func *funcptr;
I am trying to implement a function that read lines from a file and put them into a string array. But it gives me the warning:
expected char ** But argument is of type char * (*)[(sizetype)(numberOfchar)]
It was working on Windows but when I switch into Linux it stops working.
Here is the caller and the array variable :
char *hashes[numberOfchar];
PutInArray(textName, numberOfchar, &hashes);
And here is the function (the void* is for the next part of the program, threading) :
void* PutInArray(char* k, int d, char *tab[d]) {
FILE* fp = NULL;
int i;
fp = fopen(k, "r");
if(fp != NULL) {
for (i = 0; i < d; i++) {
tab[i] = (char *)malloc((34) * sizeof(char));
fgets(tab[i], 34, fp);
}
fclose(fp);
}
}
Let's see how function calls work for other types.
You have a variable int v; and a function void foo(int x) (the variable declaration and the parameter declaration look the same). You call foo(v). You also have a function void bar(int* x) (the variable declaration has one star less than the parameter declaration). You call bar(&v).
You have a variable int* v; and a function void foo(int* x) (the variable declaration and the parameter declaration look the same). You call foo(v). You also have a function void bar(int** x) (the variable declaration has one star less than the parameter declaration). You call bar(&v).
You have a variable const struct moo ***v and a function void foo(const struct moo ***x) (the variable declaration and the parameter declaration look the same). You call foo(v). You also have a function void bar(const struct moo ****x) (the variable declaration has one star less than the parameter declaration). You call bar(&v).
You have a variable char *hashes[numberOfchar] and a function void* PutInArray(char* k, int d, char *tab[d]). The variable declaration and the parameter declaration still look the same. Why on God's green earth stick & in front of the variable?
I hear you saying "but I want to pass hashes by reference, and to pass by reference I need to use &". Nope, arrays are automatically passed by reference (or rather an array automatically gets converted to a pointer of its first element; parameters of array type are similarly adjusted so that the rule formulated above just works).
For completeness, the analogue of bar would have a parameter that looks like this:
char* (*tab)[numberOfchar]
and if you had such parameter, you would have to use &hashes. But you don't need it.
Your code is almost OK. Concerning the error/warning you get, just write PutInArray(textName, numberOfchar, hashes) instead of PutInArray(textName, numberOfchar, &hashes) for the following reason:
In function PutInArray(char* k, int d, char *tab[d]), char *tab[d] has the same meaning as char*[] and char**, i.e. it behaves as a pointer to a pointer to a char.
Then you define hashes as char *hashes[numberOfchar], which is an array of pointers to char. When using hashes as function argument, hashes decays to a pointer to the first entry of the array, i.e. to a value of type char **, which matches the type of argument tab. However, if you pass &hashes, then you'd pass a pointer to type char *[], which is one indirection to much. (BTW: passing &hashes[0] would be OK).
BTW: PutInChar should either return a value or should be declared as void PutInArray(char* k, int d, char *tab[d]) (not void*).
I have come across the line of code shown below.
I think it may be a cast to a function pointer that returns void and takes a void pointer. Is that correct?
(void (*)(void *))SGENT_1_calc
Yes, it is correct. I find that not very readable, so I suggest declaring the signature of the function to be pointed:
typedef void sigrout_t(void*);
I also have the coding convention that types ending with rout_t are such types for functions signatures. You might name it otherwise, since _t is a suffix reserved by POSIX.
Later on I am casting, perhaps to call it like
((sigrout_t*) SGENT_1_calc) (someptr);
Yes, it is. The function should be looking like this
void func(void*);
But the statement is missing a target, since a cast to nothing is useless. So it should be like
func = (void (*)(void *))SGENT_1_calc;
None of the existing answers show it in direct usage, that is, taking a function pointer and casting it in order to call the function. I was playing with this to show the content of my object as json, accessing both the function and the data through anonymous pointers:
#include <stdio.h>
#include <stdlib.h>
typedef struct box1_s{
int a;
char b[50];
}box1_t;
void box1_t_print(void* ptr){
box1_t* box = (box1_t*)ptr;
printf("{\"a\": %i, \"b\": \"%s\"}", box->a, box->b);
}
int main(){
void* print = (void*)box1_t_print;
box1_t mybox = {3, "Hi folks, it's me!"};
void* ptr = &mybox;
printf("mybox = ");
((void (*)(void*))print)(ptr);
return 0;
}
Output of the program:
mybox = {"a": 3, "b": "Hi folks, it's me!"}
Yes, this is a function pointer cast.
Function pointer casts
To help you with casting functions to pointers, you can define an alias for a function pointer type as follows:
typedef void void_to_void_fct(void*);
You can also define a type for a function that takes and returns values:
typedef int math_operator(int, int);
Later, you can store a function into a function pointer type like this:
void mystery(void* arg) {
// do something nasty with the given argument
};
int add(int a, int b) {
return a + b;
}
void_to_void *ptr1 = mystery;
math_operator *ptr2 = add;
Sometimes, you have a function like print_str :
void print_str(char* str) {
printf("%s", str);
}
and you want to store it in your function pointer that is agnostic to the argument type. You can then use a cast like this:
(void (*)(void *))print_str
or
(void_to_void_fct*)print_str
Why do we use function pointers?
Function pointers allow you to "store a function" inside a variable (indeed, you store the address of the function). This is very convenient when you want to allow some code to have diferent behavior depending on user input.
For exemple, suppose we have some data and some way to decode it. We could have the following structure to keep this information:
typedef char* decoder_type(char*);
struct encoded_data {
char* data;
decoder_type *decoder_fct;
};
char* decoding_function_1(char* data) {
//...
char* decoding_function_2(char* data) {
//...
This allows storing both the data and the function to later use them together to decode the data.
int func(void) [5];
Why is above line not valid in c ? As anyone knows, function can be used as variable. But, I don't understand why compiler gives error .
Why I used that line is because I have tried to create 5 function-variable. To do so, I wrote like that, shown above.
Because it doesn't meet the C language valid syntax?
May be you should specify what are you trying to do with that sentence in order to get the answer you might be looking for.
This is not legal C syntax, period.
It is invalid in C++ too because functions cannot be put in arrays (you are trying to declare an array of five functions). However, the following works both in C and C++:
int (*func[5])(); // C++ version
int (*func[5])(void); // C version
and declares an array of five function pointers.
If you instead want a function which returns an array, in C you do
int *func(void);
and in C++ you do
int* func();
or
int (&func())[5];
which returns a reference to an array of five integers.
From the C standard (n1256):
6.7.5.3 Function declarators (including prototypes)
Constraints
1 A function declarator shall not specify a return type that is a function type or an array
type.
Functions cannot return array types or other function types. Functions can return pointers to those types, though:
int (*func(void))[5];
The syntax is a little weird looking, but it breaks down as follows:
func -- func
func(void) -- is a function taking no parameters
*func(void) -- returning a pointer
(*func(void))[5] -- to a 5-element array
int (*func(void))[5] -- of int
This isn't as useful as it looks: if you try to return a pointer to a local array, such as
int (*func(void))[5]
{
int arr[5] = {0,1,2,3,4};
return &arr;
}
the array no longer exists when the function returns; the pointer value you get back won't point to anything meaningful anymore.
If you're trying to create an array of functions, you have a similar problem; you cannot have an array of function types (6.7.5.2, paragraph 1, which includes the sentence "The element type shall not be an incomplete or function type"), although you can have an array of pointers to functions:
int (*func[5])(void);
This breaks down as
func -- func
func[5] -- is a 5-element array
*func[5] -- of pointers
(*func[5])(void) -- to functions taking no parameters
int (*func[5])(void) -- and returning int
Example:
int f0(void) { return 0; }
int f1(void) { return 1; }
int f2(void) { return 2; }
int f3(void) { return 3; }
int f4(void) { return 4; }
int main(void)
{
int (*func[5])(void) = {f0, f1, f2, f3, f4};
int i;
for (i = 0; i < 5; i++)
printf("f%d = %d\n", i, (*func[i])()); // or just func[i]()
return 0;
}
It is trying to declare a function that returns an array. This is not allowed - and it's nothing to do with syntax, it's a semantic rule, as demonstrated by the following (which has exactly the same problem, but is obviously syntactically fine):
typedef int FiveInts[5];
FiveInts func(void);
This is part of the "arrays are special" type rules in C. Function return values are not lvalues, and the only context in which a non-lvalue array could be used is as the subject of the sizeof operator. This makes functions returning array types completely useless.
try :
int *func(void);