E
This is pointer for function, then in the presented form, just as a parameter can receive a reference for an object, the parameter can receive a reference for a function.So... C has what is called https://en.wikipedia.org/wiki/Higher-order_function or https://pt.stackoverflow.com/q/227485/101 . We treat functions as if they were given.A function is of course a reference, after all access to it is given by the address of the beginning of the code written in this function, in a similar way to a vector that has a pointer for the first element of it. This is true for even static functions, but in this case the address is associated with an existing identifier in the code and it is called directly, there is not much to do with it.But it is possible to store this address in a variable, or even pass as an argument for a function that exactly expects a type that is a function. It is the same function, it is not to call a function in the argument and to pass the result of it, you pass it. Of course, it is said to pass the function without copying your code from one place to another, copy only the address.So just like a whole vector you can have a parameter more or less like int * x when it is a function that receives a whole and returns another whole would be something like that int (*x)(int), being the first int indicates that the function to be received must return a int, it will be stored in a call variable x and will receive as argument a int, as shown by the last int.I now found out that I could use the syntax without the pointer, when I learned I could only use it like this and I still need to research if it's standard, but I believe it's from the source.typedefObviously a https://pt.stackoverflow.com/q/39870/101 is a type of parameter variable, being a type it is possible to create a typedef to it and make the syntax more pleasant.It doesn't have to be just in parameter, but that's where it fits best. Could be a member of a struct, has interesting cases for this, and it is a way to simulate https://pt.stackoverflow.com/q/53108/101 .Examples:#include <stdio.h>
int func( int (*x)(int,int) ) { return x(20, 5); }
int func2( int x(int,int) ) { return x(20, 5); }
int func3( int(fn)() ) { return fn(); }
int func4( int(*fn)() ) { return fn(); }
typedef int cellulae_func(int, int);
int tabula(cellulae_func *cell, int lat, int alt) { return cell(lat, alt); }
int soma(int x, int y) { return x + y; }
int sub(int x, int y) { return x - y; }
int teste() { return 42; }
int main(void) {
printf("%d\n", tabula(soma, 20, 5));
printf("%d\n", tabula(sub, 20, 5));
printf("%d\n", func(soma));
printf("%d\n", func2(soma));
printf("%d\n", func3(teste));
printf("%d\n", func4(teste));
printf("%d\n", func4(soma)); //funciona, mas está errado
int (*funcs[2])(int x, int y);
funcs[0] = soma;
funcs[1] = sub;
printf("%d\n", func(funcs[0]));
}
See https://ideone.com/CKT2xx . And https://repl.it/join/gumillym-maniero . Also https://github.com/maniero/SOpt/blob/master/C/Function/Pointer.c .Note that I pass the static names of the functions, and as these names are actually hands, I am passing their address. On the other hand the variable that receives this pointer is used to call the function using the syntax of the parentheses. It cannot be used properly otherwise, although ancient compilers or with wild configurations allow to make damage, and of course, with a cast everything is allowed, even if the result is bad.The ideal is to use functions with compatible signatures, it is indefinite behavior to use an inadequate one, as demonstrated in one of the lines.The two functions with name x have the same signature, which is compatible with both soma the sub defined below. O typedef is compatible with the same signature. The names could be different, because in the background this is only the name of the variable. The name fn have another signature.UsageThe advantage of having this is that they can dynamically configure what to perform in a given context. What's that? https://pt.stackoverflow.com/a/153042/101 (at least one form of it). And it's a https://pt.stackoverflow.com/q/4731/101 in many cases, since functions can be placed in a vector or other data structure, as demonstrated above in the example. So whenever any action need configured on demand, as the need for the moment, this type of function is interesting.It is widely used as https://pt.stackoverflow.com/q/27177/101 , where you call an algorithm that at a given time needs to perform something that it still doesn't know what it is, that is, it responds to something configurable by the caller. So think about handlers, events.The C itself has algorithms that expect a callback, e.g. https://en.cppreference.com/w/c/algorithm/qsort where you say how it should perform data comparison to sort the way you want, so by taking the specific data, deciding whether to do something extra operation with the data, such as giving a upper, whether it will be growing or decreasing.Creativity allows to make different compositions, could for example create a dictionary with (points to) functions as values of it and according to something typed by the user or obtaining information otherwise in runtime call the proper function, which is very similar to what a language with enough dynamism and having a https://pt.stackoverflow.com/q/128845/101 allows to do.If it's anything static it can be a https://en.wikipedia.org/wiki/Branch_table .An application like the flame https://en.wikipedia.org/wiki/Lazy_evaluation , where you define what you want to do, but do not want it to be done at that time, then you "pass the code" somewhere and at the proper time the code is called.LimitationC has no syntax lick that could declare the function at the place you need. Something like that can't:printf("%d\n", tabula((int x, int y) => x + y, 20, 5));
C also does not have a mechanism of own capture of various of the current scope to load along with the past function as parameter, something that other languages possess, but nothing prevents you from manually creating this capability, only it is not convenient.ExampleThe most obvious example of use is with sorting algorithms where you need to say what is the criterion of what is lower than the other, until you decide the exact key or whether the order should be growing or decreasing. So the function https://en.cppreference.com/w/c/algorithm/qsort C default already receives a function as parameter. In C++ this is much more efficient.#include <stdio.h>
#include <stdlib.h>
int compare(const void* left, const void* right) { return ((int)right - (int)left); }
int main() {
int (cmp) (const void , const void*) = &compare;
int array[] = {1, 8, 0, 4, 6, 5, 1, 6, 9, 7};
qsort(array, 10, sizeof(int), cmp);
for (int i = 0; i < 10; i++) printf("%d ", array[i]);
}
See https://ideone.com/hF9qDE . And https://repl.it/join/swjpxchs-maniero . Also https://github.com/maniero/SOpt/blob/master/C/Function/QuickSortExample.c .Exercise: This generates a https://pt.stackoverflow.com/q/325088/101 ? The question is a catch.C++This mechanism should not be used in C++, except for compatibility, long ago it has libraries that deal with it better, and since 2011 has https://pt.stackoverflow.com/q/34907/101 . And even some specific uses the C++ has better solution.AssemblySee how it looks after compiled by GCC (other compilers are theoretically less efficient): push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
mov edx, DWORD PTR [rbp-4]
mov eax, DWORD PTR [rbp-8]
add eax, edx
pop rbp
ret
func:
push rbp
mov rbp, rsp
mov esi, 5
mov edi, 20
call soma
pop rbp
ret
func2:
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
mov esi, 5
mov edi, 20
call rax
leave
ret
tabula:
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov DWORD PTR [rbp-12], esi
mov DWORD PTR [rbp-16], edx
mov ecx, DWORD PTR [rbp-16]
mov edx, DWORD PTR [rbp-12]
mov rax, QWORD PTR [rbp-8]
mov esi, ecx
mov edi, edx
call rax
leave
ret
main:
push rbp
mov rbp, rsp
mov edx, 5
mov esi, 20
mov edi, OFFSET FLAT:soma
call tabula
mov eax, 0
call func
mov edi, OFFSET FLAT:soma
call func2
mov eax, 0
pop rbp
ret
Better visually https://gcc.godbolt.org/z/af35LF .It can be noted that the call suffers indirection and has more complex instructions. What may not be so obvious is extra access to memory and this can be slower and makes more difference than some more instructions. And you can see that everything that is definition of types and contracts is thrown out.